springboot集成shiro并利用jwt完成登录验证及权限验证
最近想在一个后台管理系统加上多角色多权限的功能,了解到了现有的安全框架后决定使用shiro,学习成本相对较低,而shiro默认使用session机制来实现用户的登录验证,而原先项目里面已使用jwt机制,并且前后端项目分离,所以对shiro加以改进。
数据库
首先在有用户表的前提下,需要有角色表和权限表,还有他们的关联表,在此简单的介绍下表结构,相信大家都会创建啦!
user id,name
role id,name
user_role user_id,role_id
menu id,name,permisson
role_menu role_id,menu_id
依赖
maven添加shiro所需要的依赖包
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.5.3</version>
</dependency>
<!-- shiro-core -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version> 1.5.3</version>
</dependency>
配置类
是一个工具中间件就需要配置,按照springboot的机制,就使用注解来写配置类,在类上面添加@Configuration来声明是一个配置类,改为使用jwt认证其实就是需要做关闭shiro默认使用的session机制,和自定义一个过滤器,不使用shiro默认的authc过滤器
注入一个ShiroFilterFactoryBean,查看该类源码可知要传入的参数
private static final transient Logger log = LoggerFactory.getLogger(ShiroFilterFactoryBean.class);
private SecurityManager securityManager;
private Map<String, Filter> filters = new LinkedHashMap();
private Map<String, String> filterChainDefinitionMap = new LinkedHashMap();
private String loginUrl;
private String successUrl;
private String unauthorizedUrl;
private AbstractShiroFilter instance;
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
// 必须设置 SecurityManager
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
// setLoginUrl 如果不设置值,默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射
//前后端分离项目中该链接应该为后端接口的访问url,通过该接口返回需要登录的状态码,由前端跳转至登录页面
// shiroFilter.setLoginUrl("/user/login");
// 设置无权限时跳转的 url;
// shiroFilter.setUnauthorizedUrl("/user/test");
// 添加自己的过滤器并且取名为jwt
LinkedHashMap<String, Filter> filterMap = new LinkedHashMap<>();
filterMap.put("jwt", this.jwtFilter());
shiroFilter.setFilters(filterMap);
// 设置拦截器
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
// //anon:无参,开放权限,可以理解为匿名用户或游客
filterChainDefinitionMap.put("/user/login", "anon");
filterChainDefinitionMap.put("/movie/listPage", "anon");
filterChainDefinitionMap.put("/movie/info", "anon");
// //其余接口一律拦截
// //主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截
// //authc:无参,需要认证
filterChainDefinitionMap.put("/**", "jwt");
shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilter;
}
SecurityManager是一个安全管理器,这个类组合了登陆,登出,权限,session的处理,由于我们使用自己的jwt机制,所以要在这个类里面关闭shiro自带的session机制
@Bean("securityManager")
public SecurityManager securityManager(UserRealm userRealm) {
/*
* 关闭shiro自带的session,详情见文档
* http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
*/
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
subjectDAO.setSessionStorageEvaluator