SpringBoot与Shiro整合权限管理实战
作者 : Stanley 罗昊
【转载请注明出处和署名,谢谢!】
*观看本文章需要有一定SpringBoot整合经验*
Shiro框架简介
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。使用Shiro的易于理解的API,可以快速、轻松地获得任何应用程序,
从最小的移动应用程序到最大的网络和企业应用程序。
分析Shiro的核心API
其实,Shiro的核心类有三个,分别是:
1.Subject:这个类呢,我们称之当前用户的主体,这个用户的主体包含了登陆、注销等等的一些方法,还有一些判断授权的一些方法;
2.SecurityManager:这个名称翻译过来就是,安全管理器的意思;
3.Realm:这个Realm呢其实我们Shiro去链接数据库的一个桥梁,因为,我们的程序需要去操作数据库去获取一些用户的信息,这些操作都需要Realm去完成;
这个三个API呢,都存在一些关系,比如.SecurityManager是需要去关联我们的Realm,Subject是需要把操作交给我们的SecurityManager,总结下来就是,Subject是需要去管理我们的SecurityManager,而SecurityManager去关联我们的Realm;
以上就是对Shiro的核心API进行的一些分析;
分析完之后,我们接下来就直接用SpringBoot与Shiro的整合,我们来看下它整合的关键步骤
SpringBoot整合Shiro
那么这个整合首先第一步需要导入Shiro的依赖;
【因为我用的是Gradle,所以仅展示Gradle用法】
1.修改.gradle文件,添加以下依赖
//Thymeleaf模板引擎,因为我用模板引擎所以我添加了此依赖 compile group: 'org.thymeleaf', name: 'thymeleaf', version: '3.0.11.RELEASE' //Shiro compile group: 'org.apache.shiro', name: 'shiro-web', version: '1.4.0' compile group: 'org.apache.shiro', name: 'shiro-core', version: '1.4.0' // https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring compile group: 'org.apache.shiro', name: 'shiro-spring', version: '1.4.0'
2.编写Shiro的配置类
配置类需要三样API,分别是:
/** * 创建ShiroFilterFactoryBean * shiro过滤bean */ /** * 创建DefaultWebSecurityManager */ /** * 创建Realm */
如图:
3.自定义Realm类
因为我们需要在配置类中创建出Realm对象,所以我们需要建一个名为Realm的类:
创建后,需要继承一个方法,这个方法是Shiro提供的:
/** * 自定义Realm */ public class UserRealm extends AuthorizingRealm { //执行授权逻辑 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { return null; } //执行认证逻辑 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException { return null; }
4.在配置类中new出Realm
Shiro配置配置类
package com.lh.shiroStudy.shiro; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.LinkedHashMap; import java.util.Map; /** * Shiro配置类 */ //@Configuration,声明本类是一个配置类 @Configuration public class ShiroConfig { /** * 创建ShiroFilterFactoryBean * shiro过滤bean */ @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){ ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //设置安全管理器 shiroFilterFactoryBean.setSecurityManager(securityManager); //添加Shiro过滤器 /** * Shiro内置过滤器,可以实现权限相关的拦截器 * 常用的过滤器: * anon: 无需认证(登录)可以访问 * authc: 必须认证才可以访问 * user: 如果使用rememberMe功能可以直接访问 * perms: 该资源必须得到资源权限才可以访问 * role: 该资源必须得到角色权限才可以访问 */ Map<String,String>filterMap = new LinkedHashMap<String, String>(); //左边编写拦截路径 filterMap.put("/add","authc"); filterMap.put("/update","authc"); filterMap.put("/testThymeleaf","authc"); //授权过滤器 //注意:当前授权拦截后,shiro会自动跳转未授权页面 filterMap.put("/add","perms[user:add]"); //修改跳转的登陆页面 shiroFilterFactoryBean.setLoginUrl("/toLogin"); //转跳至未授权页面【友好提示】 shiroFilterFactoryBean.setUnauthorizedUrl("/aaaaaa");//懒省事所以没有aaaa这个页面,如果需要,请在Contoller中添加 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); return shiroFilterFactoryBean; } /** * 创建DefaultWebSecurityManager */ @Bean(name = "securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("UserRealm") UserRealm userRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(userRealm); return securityManager; } /** * 创建Realm */ @Bean(name = "UserRealm") public UserRealm getRealm(){ return new UserRealm(); } }
Realm类
package com.lh.shiroStudy.shiro; 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; /** * 自定义Realm */ public class UserRealm extends AuthorizingRealm { //执行授权逻辑 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //给资源进行授权 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //添加资源的授权字符串 //info.addStringPermission("user:add"); //到数据库查询当前登陆用户的授权字符串 /** * <!-演示状态-!> * 获取当前用户 * Subject subject = SecurityUtils.getSubject(); * User user = (User)subject.getPrincipal(); * User dbUser = userService.findById(id) * info.addStringPermission(dbUser.getPerms()); * </!-演示状态-!> */ System.out.println("执行授权逻辑"); return null; } //执行认证逻辑 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException { System.out.println("执行认证逻辑"); //假设数据库账号与密码是如下 String username = "admin"; String password = "123456"; /** * 编写Shiro判断逻辑,比对用户名和密码 */ //1.判断用户名 UsernamePasswordToken token =(UsernamePasswordToken)arg0; //User user = userService.findByName(token.getUsername()); if (user == null){ //用户名不存在 return null;//如果返回null,Shiro底层会抛出UnknowAccountException } //2.判断密码 /** * 有三个参数 * 1.需要返回给login * 2.是数据库的密码,将数据库密码返回,Shiro会自动判断 * 3.是Shiro的名字 */ return new SimpleAuthenticationInfo(user,password,""); } }