概述
本文搭建环境使用Springboot-2.1.3版本,数据库使用mysql,持久层使用jpa
简单实现了用户权限登录的功能,实现的比较简洁,实际项目中根据需求进行修改
1. Pom文件
首先导入需要的包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>Shiro</groupId>
<artifactId>Shiro</artifactId>
<version>Shiro-1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.20</version>
</dependency>
<!-- 安全框架apache shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
</project>
直接导入就可以了。
2.配置文件application.yml
server:
port: 8081
#database
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/shiro?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
username: root
password: 123456
initialization-mode: always
schema: classpath:schema.sql
3.数据库配置
数据源的配置
package com.shiro.build.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
/**
* @author FCZ
* @since 2019/3/1 15:22
* 数据源配置
*/
@Configuration
public class DatabaseConfiguration {
@ConfigurationProperties(prefix = "spring.datasource")
@Bean(name = "dataSource")
public DataSource dataSource() {
return new DruidDataSource();
}
}
druid连接池配置
package com.shiro.build.config;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Druid数据源配置
*/
@Configuration
public class DruidConfig {
@Bean
public ServletRegistrationBean druidServlet() {
ServletRegistrationBean reg = new ServletRegistrationBean();
reg.setServlet(new StatViewServlet());
reg.addUrlMappings("/druid/*");
reg.addInitParameter("loginUsername", "admin");
reg.addInitParameter("loginPassword", "admin");
return reg;
}
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
return filterRegistrationBean;
}
}
4.获取用户数据
使用jpa查询用户权限 以及用户信息,详情请查看GitHub中的代码.
5.Shiro的实现
最重要的shiro的配置实现,主要使用两个类进行配置
MyShiroRealm继承AuthorizingRealm,实现AuthorizingRealm的doGetAuthorizationInfo()和doGetAuthenticationInfo()方法.用于进行登录时的认证和授权。
package com.shiro.build.shiro;
import com.shiro.build.entity.RoleInfo;
import com.shiro.build.entity.UserInfo;
import com.shiro.build.respository.RoleRepository;
import com.shiro.build.respository.UserRepository;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author FCZ
* @since 2019/3/1 16:22
*/
public class MyShiroRealm extends AuthorizingRealm {
private static final Logger logger = LoggerFactory.getLogger(MyShiroRealm.class);
@Autowired
private UserRepository userRepository;
@Autowired
private RoleRepository roleRepository;
/**
* 权限认证 给登陆的用户授予角色和权限
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
logger.info("执行Shiro权限认证");
//获取当前登录输入的用户名
String loginName = (String) super.getAvailablePrincipal(principalCollection);
// 到数据库查是否有此对象
UserInfo loginUserInfo = userRepository.findUserInfoByUserName(loginName);
if (loginUserInfo != null) {
// 取得权限信息
List<RoleInfo> roleInfoList = roleRepository.getRoleInfoByUserID(loginUserInfo.getId());
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
Set<String> userRoles = new HashSet<>();
for(RoleInfo roleInfo : roleInfoList) {
userRoles.add(roleInfo.getRoleName());
}
// info.addStringPermissions(userPermissions);
info.addRoles(userRoles);
return info;
}
// 返回null的话,就会导致任何用户访问被拦截的请求时,都会自动跳转到unauthorizedUrl指定的地址
return null;
}
/**
* 登录认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//UsernamePasswordToken 对象用来存放提交的登录信息
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
//查出是否有此用户
UserInfo loginUserInfo = userRepository.findUserInfoByUserName(token.getUsername());
if (loginUserInfo != null) {
// 若存在,将此用户存放到登录认证info中
// 第一个参数为成功后存储到session中的信息 获取通过 SecurityUtils.getSubject().getPrincipal()进行获取
return new SimpleAuthenticationInfo(loginUserInfo, loginUserInfo.getPassword(), getName());
}
return null;
}
}
ShiroConfiguration类,对shiro进行配置,分别进行了对realm的注册、用户密码的加密规则以及对URL的过滤规则、和权限控制
package com.shiro.build.shiro;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
/**
* Created by hp on 2017/7/26.
*/
@Configuration
public class ShiroConfiguration {
private static final Logger logger = LoggerFactory.getLogger(ShiroConfiguration.class);
/**
* 安全管理器
*
* @return
*/
@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(getMyRealm());
return securityManager;
}
/**
* Realm
*
* @return
*/
@Bean(name = "myRealm")
public MyShiroRealm getMyRealm() {
MyShiroRealm realm = new MyShiroRealm();
realm.setCredentialsMatcher(hashedCredentialsMatcher());
return realm;
}
/**
* 加密规则
*
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//md5加密 散列1次
hashedCredentialsMatcher.setHashAlgorithmName("md5");
hashedCredentialsMatcher.setHashIterations(1);
return hashedCredentialsMatcher;
}
/* @Bean
public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}*/
/**
* 开启Shiro的注解支持
*/
@Bean
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
daap.setProxyTargetClass(true);
return daap;
}
/**
* 开启aop注解支持
*/
@Bean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
aasa.setSecurityManager(securityManager());
return aasa;
}
/**
* 过滤规则
*
* @return
*/
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilter() {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager());
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/");
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorizedRole");
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
// authc 必须验证后才能访问
// anon 不需要验证
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/druid/**", "anon");
filterChainDefinitionMap.put("/api/**", "authc");
// 除了使用注解@RequiresRoles 配置权限 还可以通过下面进行配置
filterChainDefinitionMap.put("/user/**", "roles[USER]");
filterChainDefinitionMap.put("/admin/**", "roles[ADMIN]");
// "/**" 拦截 必须放到最下面
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
// 异常配置
// 使用@RequiresRoles 注解,不跳转
@Bean
public SimpleMappingExceptionResolver resolver() {
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
Properties properties = new Properties();
properties.setProperty("org.apache.shiro.authz.UnauthorizedException", "/unauthorizedRole");
resolver.setExceptionMappings(properties);
return resolver;
}
}
基本这样,就已经完成了项目的搭建工作。
然后启动项目调用对应接口查看权限。
登录用户 该用户有USER权限,没有ADMIN权限。
调用USER权限接口,查看是否调用成功
调用ADMIN权限接口,查看是否调用成功
结果显示与配置的是一致的。
下面是我搭建环境时候遇见的一些问题的总结
1. 配置未授权url后不生效
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorizedRole");
使用这种方式配置后,访问未授权的接口,并没有跳转到"/unauthorizedRole"接口,只会提示404。
filterChainDefinitionMap.put("/user/**", "roles[USER]");
filterChainDefinitionMap.put("/admin/**", "roles[ADMIN]");
使用这样的方式进行配置,就可以跳转到"/unauthorizedRole"接口。
或者在配置文件中,增加对异常的处理
@Bean
public SimpleMappingExceptionResolver resolver() {
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
Properties properties = new Properties();
properties.setProperty("org.apache.shiro.authz.UnauthorizedException", "/unauthorizedRole");
resolver.setExceptionMappings(properties);
return resolver;
}
这样就可以解决上述问题。
2.第一次调用登录接口会提示404错误。
因为第一次访问没有存在的cookie信息,会导致这个问题。再次请求即可。正式发布使用不会出现这种问题。
Github地址 GitHub
最后
以上就是有魅力小蚂蚁为你收集整理的SpringBoot2 搭建 Shiro环境 实现权限控制登录1. Pom文件2.配置文件application.yml3.数据库配置4.获取用户数据5.Shiro的实现的全部内容,希望文章能够帮你解决SpringBoot2 搭建 Shiro环境 实现权限控制登录1. Pom文件2.配置文件application.yml3.数据库配置4.获取用户数据5.Shiro的实现所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复