SpringBoot2.0高级案例(01): 整合 Shiro 框架,实现用户权限管理

一、Shiro简介

1、基础概念

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。作为一款安全框架Shiro的设计相当巧妙。Shiro的应用不依赖任何容器,它不仅可以在JavaEE下使用,还可以应用在JavaSE环境中。

2、核心角色

1)Subject:认证主体

代表当前系统的使用者,就是用户,在Shiro的认证中,认证主体通常就是userName和passWord,或者其他用户相关的唯一标识。

2)SecurityManager:安全管理器

Shiro架构中最核心的组件,通过它可以协调其他组件完成用户认证和授权。实际上,SecurityManager就是Shiro框架的控制器。

3)Realm:域对象

定义了访问数据的方式,用来连接不同的数据源,如:关系数据库,配置文件等等。

3、核心理念

Shiro自己不维护用户和权限,通过Subject用户主体和Realm域对象的注入,完成用户的认证和授权。

二、整合SpringBoot2框架

1、核心依赖

1<dependency> 2 <groupid>org.apache.shiro</groupid> 3 <artifactid>shiro-core</artifactid> 4 <version>1.4.0</version> 5</dependency> 6<dependency> 7 <groupid>org.apache.shiro</groupid> 8 <artifactid>shiro-spring</artifactid> 9 <version>1.4.0</version> 10</dependency>

2、Shiro核心配置

1@Configuration 2public class ShiroConfig { 3 /** 4 * Session Manager:会话管理 5 * 即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中; 6 * 会话可以是普通JavaSE环境的,也可以是如Web环境的; 7 */ 8 @Bean("sessionManager") 9 public SessionManager sessionManager(){ 10 DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); 11 //设置session过期时间 12 sessionManager.setGlobalSessionTimeout(60 * 60 * 1000); 13 sessionManager.setSessionValidationSchedulerEnabled(true); 14 // 去掉shiro登录时url里的JSESSIONID 15 sessionManager.setSessionIdUrlRewritingEnabled(false); 16 return sessionManager; 17 } 18 19 /** 20 * SecurityManager:安全管理器 21 */ 22 @Bean("securityManager") 23 public SecurityManager securityManager(UserRealm userRealm, SessionManager sessionManager) { 24 DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); 25 securityManager.setSessionManager(sessionManager); 26 securityManager.setRealm(userRealm); 27 return securityManager; 28 } 29 /** 30 * ShiroFilter是整个Shiro的入口点,用于拦截需要安全控制的请求进行处理 31 */ 32 @Bean("shiroFilter") 33 public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { 34 ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); 35 shiroFilter.setSecurityManager(securityManager); 36 shiroFilter.setLoginUrl("/userLogin"); 37 shiroFilter.setUnauthorizedUrl("/"); 38 Map<string, string> filterMap = new LinkedHashMap&lt;&gt;(); 39 filterMap.put("/userLogin", "anon"); 40 shiroFilter.setFilterChainDefinitionMap(filterMap); 41 return shiroFilter; 42 } 43 /** 44 * 管理Shiro中一些bean的生命周期 45 */ 46 @Bean("lifecycleBeanPostProcessor") 47 public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { 48 return new LifecycleBeanPostProcessor(); 49 } 50 /** 51 * 扫描上下文,寻找所有的Advistor(通知器) 52 * 将这些Advisor应用到所有符合切入点的Bean中。 53 */ 54 @Bean 55 public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { 56 DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator(); 57 proxyCreator.setProxyTargetClass(true); 58 return proxyCreator; 59 } 60 /** 61 * 匹配所有加了 Shiro 认证注解的方法 62 */ 63 @Bean 64 public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { 65 AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); 66 advisor.setSecurityManager(securityManager); 67 return advisor; 68 } 69}

3、域对象配置

1@Component 2public class UserRealm extends AuthorizingRealm { 3 @Resource 4 private SysUserMapper sysUserMapper ; 5 @Resource 6 private SysMenuMapper sysMenuMapper ; 7 /** 8 * 授权(验证权限时调用) 9 * 获取用户权限集合 10 */ 11 @Override 12 public AuthorizationInfo doGetAuthorizationInfo 13 (PrincipalCollection principals) { 14 SysUserEntity user = (SysUserEntity)principals.getPrimaryPrincipal(); 15 if(user == null) { 16 throw new UnknownAccountException("账号不存在"); 17 } 18 List<string> permsList; 19 //默认用户拥有最高权限 20 List<sysmenuentity> menuList = sysMenuMapper.selectList(); 21 permsList = new ArrayList&lt;&gt;(menuList.size()); 22 for(SysMenuEntity menu : menuList){ 23 permsList.add(menu.getPerms()); 24 } 25 //用户权限列表 26 Set<string> permsSet = new HashSet&lt;&gt;(); 27 for(String perms : permsList){ 28 if(StringUtils.isEmpty(perms)){ 29 continue; 30 } 31 permsSet.addAll(Arrays.asList(perms.trim().split(","))); 32 } 33 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); 34 info.setStringPermissions(permsSet); 35 return info; 36 } 37 /** 38 * 认证(登录时调用) 39 * 验证用户登录 40 */ 41 @Override 42 protected AuthenticationInfo doGetAuthenticationInfo( 43 AuthenticationToken authToken) throws AuthenticationException { 44 UsernamePasswordToken token = (UsernamePasswordToken)authToken; 45 //查询用户信息 46 SysUserEntity user = sysUserMapper.selectOne(token.getUsername()); 47 //账号不存在 48 if(user == null) { 49 throw new UnknownAccountException("账号或密码不正确"); 50 } 51 //账号锁定 52 if(user.getStatus() == 0){ 53 throw new LockedAccountException("账号已被锁定,请联系管理员"); 54 } 55 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo 56 (user, user.getPassword(), 57 ByteSource.Util.bytes(user.getSalt()), 58 getName()); 59 return info; 60 } 61 @Override 62 public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) { 63 HashedCredentialsMatcher shaCredentialsMatcher = new HashedCredentialsMatcher(); 64 shaCredentialsMatcher.setHashAlgorithmName(ShiroUtils.hashAlgorithmName); 65 shaCredentialsMatcher.setHashIterations(ShiroUtils.hashIterations); 66 super.setCredentialsMatcher(shaCredentialsMatcher); 67 } 68}

4、核心工具类

1public class ShiroUtils { 2 /** 加密算法 */ 3 public final static String hashAlgorithmName = "SHA-256"; 4 /** 循环次数 */ 5 public final static int hashIterations = 16; 6 public static String sha256(String password, String salt) { 7 return new SimpleHash(hashAlgorithmName, password, salt, hashIterations).toString(); 8 } 9 // 获取一个测试账号 admin 10 public static void main(String[] args) { 11 // 3743a4c09a17e6f2829febd09ca54e627810001cf255ddcae9dabd288a949c4a 12 System.out.println(sha256("admin","123")) ; 13 } 14 /** 15 * 获取会话 16 */ 17 public static Session getSession() { 18 return SecurityUtils.getSubject().getSession(); 19 } 20 /** 21 * Subject:主体,代表了当前“用户” 22 */ 23 public static Subject getSubject() { 24 return SecurityUtils.getSubject(); 25 } 26 public static SysUserEntity getUserEntity() { 27 return (SysUserEntity)SecurityUtils.getSubject().getPrincipal(); 28 } 29 public static Long getUserId() { 30 return getUserEntity().getUserId(); 31 } 32 public static void setSessionAttribute(Object key, Object value) { 33 getSession().setAttribute(key, value); 34 } 35 public static Object getSessionAttribute(Object key) { 36 return getSession().getAttribute(key); 37 } 38 public static boolean isLogin() { 39 return SecurityUtils.getSubject().getPrincipal() != null; 40 } 41 public static void logout() { 42 SecurityUtils.getSubject().logout(); 43 } 44}

5、自定义权限异常提示

1@RestControllerAdvice 2public class ShiroException { 3 @ExceptionHandler(AuthorizationException.class) 4 public String authorizationException (){ 5 return "抱歉您没有权限访问该内容!"; 6 } 7 @ExceptionHandler(Exception.class) 8 public String handleException(Exception e){ 9 return "系统异常!"; 10 } 11}

三、案例演示代码

1、测试接口

1@RestController 2public class ShiroController { 3 private static Logger LOGGER = LoggerFactory.getLogger(ShiroController.class) ; 4 @Resource 5 private SysMenuMapper sysMenuMapper ; 6 /** 7 * 登录测试 8 * http://localhost:7011/userLogin?userName=admin&amp;passWord=admin 9 */ 10 @RequestMapping("/userLogin") 11 public void userLogin ( 12 @RequestParam(value = "userName") String userName, 13 @RequestParam(value = "passWord") String passWord){ 14 try{ 15 Subject subject = ShiroUtils.getSubject(); 16 UsernamePasswordToken token = new UsernamePasswordToken(userName, passWord); 17 subject.login(token); 18 LOGGER.info("登录成功"); 19 }catch (Exception e) { 20 e.printStackTrace(); 21 } 22 } 23 /** 24 * 服务器每次重启请求该接口之前必须先请求上面登录接口 25 * http://localhost:7011/menu/list 获取所有菜单列表 26 * 权限要求:sys:user:shiro 27 */ 28 @RequestMapping("/menu/list") 29 @RequiresPermissions("sys:user:shiro") 30 public List list(){ 31 return sysMenuMapper.selectList() ; 32 } 33 /** 34 * 用户没有该权限,无法访问 35 * 权限要求:ccc:ddd:bbb 36 */ 37 @RequestMapping("/menu/list2") 38 @RequiresPermissions("ccc:ddd:bbb") 39 public List list2(){ 40 return sysMenuMapper.selectList() ; 41 } 42 /** 43 * 退出测试,退出后没有任何权限 44 */ 45 @RequestMapping("/userLogOut") 46 public String logout (){ 47 ShiroUtils.logout(); 48 return "success" ; 49 } 50}

2、测试流程

11)、登录后取得权限 2http://localhost:7011/userLogin?userName=admin&amp;passWord=admin 32)、访问有权限接口 4http://localhost:7011/menu/list 53)、访问无权限接口 6http://localhost:7011/menu/list2 74)、退出登录 8http://localhost:7011/userLogOut

四、源代码地址

1GitHub地址:知了一笑 2https://github.com/cicadasmile/middle-ware-parent 3码云地址:知了一笑 4https://gitee.com/cicadasmile/middle-ware-parent

</string></sysmenuentity></string></string,>

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )