SpringBoot怎么整合Shiro实现权限控制
SpringBoot怎么整合Shiro实现权限控制
这篇文章主要介绍“SpringBoot怎么整合Shiro实现权限控制”,在日常操作中,相信很多人在SpringBoot怎么整合Shiro实现权限控制问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”SpringBoot怎么整合Shiro实现权限控制”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
1、SpringBoot整合Shiro
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。
1.1、shiro简介
shiro有个核心组件,分别为Subject、SecurityManager和Realms
Subject:相当于当前操作的”用户“,这个用户不一定是一个具体的人,是一个抽象的概念,表明的是和当前程序进行交互的任何东西,例如爬虫、脚本、等等。所有的Subject都绑定到SecurityManager上,与 Subject 的所有交互都会委托给 SecurityManager;可以把 Subject 认为是一个门面;SecurityManager 才是实际的执行者。
SecurityManager:这个是shiro框架的核心,所有与安全相关的操作都会与它进行交互,它管理者所有的Subject。
Realms:充当了Shiro与应用安全数据间的”桥梁“,当对用户执行认证(登录)和授权(访问控制)验证时,SecurityManager 需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色 / 权限进行验证用户是否能进行操作。
1.2、代码的具体实现
1.2.1、Maven的配置
<!--shiro--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-starter</artifactId><version>1.7.1</version></dependency><!--shiro整合thymeleaf--><dependency><groupId>com.github.theborakompanioni</groupId><artifactId>thymeleaf-extras-shiro</artifactId><version>2.0.0</version></dependency><!--shiro缓存--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-ehcache</artifactId><version>1.7.1</version></dependency>
shiro默认是与jsp进行使用的,而这里是shiro整合thymeleaf所有要导入shiro整合thymeleaf的jar包
1.2.2、整合需要实现的类
一般来说整合只需要完成两个类的实现即可
一个是 ShiroConfig 一个是 CustomerRealm
如果需要添加shiro缓存并且不是自带的缓存而是redis缓存还需要进行另外两个类的编写
一个是 RedisCache 一个是 RedisCacheManager
1.2.3、项目结构
1.2.4、ShiroConfig的实现
未加shiro的缓存
packagecom.yuwen.config;importat.pollux.thymeleaf.shiro.dialect.ShiroDialect;importcom.yuwen.shiro.cache.RedisCacheManager;importcom.yuwen.shiro.realm.CustomerRealm;importorg.apache.shiro.authc.credential.HashedCredentialsMatcher;importorg.apache.shiro.realm.Realm;importorg.apache.shiro.spring.web.ShiroFilterFactoryBean;importorg.apache.shiro.web.mgt.DefaultWebSecurityManager;importorg.springframework.beans.factory.annotation.Qualifier;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importjava.util.HashMap;importjava.util.Map;@ConfigurationpublicclassShiroConfig{//让页面shiro标签生效@BeanpublicShiroDialectshiroDialect(){returnnewShiroDialect();}//1、创建shiroFilter负责拦截所有请求@BeanpublicShiroFilterFactoryBeanshiroFilterFactoryBean(DefaultWebSecurityManagerdefaultWebSecurityManager){ShiroFilterFactoryBeanfactoryBean=newShiroFilterFactoryBean();//给filter设置安全管理factoryBean.setSecurityManager(defaultWebSecurityManager);//配置系统的受限资源//配置系统公共资源全部都能访问的设置anonMap<String,String>map=newHashMap<>();map.put("/main","authc");//请求这个资源需要认证和授权authc表示需要认证后才能访问map.put("/admin","roles[admin]");//表示admin角色才能访问roles[]表示需要什么角色才能访问map.put("/manage","perms[user:*:*]");//表示需要user:*:*权限才能访问perms[]表示需要什么权限才能访问//访问需要认证的页面如果未登录会跳转到/login路由进行登陆factoryBean.setLoginUrl("/login");//访问未授权页面会自动跳转到/unAuth路由factoryBean.setUnauthorizedUrl("/unAuth");factoryBean.setFilterChainDefinitionMap(map);returnfactoryBean;}//2、创建安全管理器@BeanpublicDefaultWebSecurityManagerdefaultWebSecurityManager(@Qualifier("getRealm")Realmrealm){DefaultWebSecurityManagersecurityManager=newDefaultWebSecurityManager();//给安全管理器设置securityManager.setRealm(realm);returnsecurityManager;}//3、创建自定义的realm@BeanpublicRealmgetRealm(){CustomerRealmcustomerRealm=newCustomerRealm();//修改凭证校验匹配器HashedCredentialsMatchercredentialsMatcher=newHashedCredentialsMatcher();//设置加密算法为md5credentialsMatcher.setHashAlgorithmName("MD5");//设置散列次数credentialsMatcher.setHashIterations(1024);customerRealm.setCredentialsMatcher(credentialsMatcher);returncustomerRealm;}}
因为一般在数据库中设置明文密码不安全,所有我这里对密码进行了md5加密,我的加密方式为:密码 = 密码+盐+散列次数 而后进行MD5加密 所以这里创建自定义的realm时需要进行设置匹配器这样登录时密码才能匹配成功
1.2.5、CustomerRealm的实现
packagecom.yuwen.shiro.realm;importcom.yuwen.pojo.User;importcom.yuwen.pojo.vo.ViewPerms;importcom.yuwen.pojo.vo.ViewRole;importcom.yuwen.service.UserService;importcom.yuwen.shiro.salt.MyByteSource;importorg.apache.shiro.authc.AuthenticationException;importorg.apache.shiro.authc.AuthenticationInfo;importorg.apache.shiro.authc.AuthenticationToken;importorg.apache.shiro.authc.SimpleAuthenticationInfo;importorg.apache.shiro.authz.AuthorizationInfo;importorg.apache.shiro.authz.SimpleAuthorizationInfo;importorg.apache.shiro.realm.AuthorizingRealm;importorg.apache.shiro.subject.PrincipalCollection;importorg.apache.shiro.util.CollectionUtils;importorg.springframework.util.ObjectUtils;importjavax.annotation.Resource;importjava.util.List;//自定义realmpublicclassCustomerRealmextendsAuthorizingRealm{@ResourceprivateUserServiceuserService;//授权@OverrideprotectedAuthorizationInfodoGetAuthorizationInfo(PrincipalCollectionprincipalCollection){//获取身份信息StringprimaryPrincipal=(String)principalCollection.getPrimaryPrincipal();//根据主身份信息获取角色和权限信息List<ViewRole>roles=userService.findRolesByUsername(primaryPrincipal);if(!CollectionUtils.isEmpty(roles)){SimpleAuthorizationInfosimpleAuthorizationInfo=newSimpleAuthorizationInfo();roles.forEach(viewRole->{simpleAuthorizationInfo.addRole(viewRole.getName());//权限信息List<ViewPerms>perms=userService.findPermsByRoleId(viewRole.getName());if(!CollectionUtils.isEmpty(perms)){perms.forEach(viewPerms->{simpleAuthorizationInfo.addStringPermission(viewPerms.getPName());});}});returnsimpleAuthorizationInfo;}returnnull;}//认证@OverrideprotectedAuthenticationInfodoGetAuthenticationInfo(AuthenticationTokenauthenticationToken)throwsAuthenticationException{//获取登入的身份信息Stringprincipal=(String)authenticationToken.getPrincipal();Useruser=userService.findByUsername(principal);if(!ObjectUtils.isEmpty(user)){//ByteSource.Util.bytes(user.getSalt())通过这个工具将盐传入//如果身份认证验证成功,返回一个AuthenticationInfo实现;returnnewSimpleAuthenticationInfo(user.getUsername(),user.getPassword(),newMyByteSource(user.getSalt()),this.getName());}returnnull;}}
在登录时会自动调用这个身份验证 在验证时如果出错,会报异常,我在controller层接收了异常并处理
controller层中登录时的异常处理
@PostMapping("/login")publicStringlogin(Stringusername,Stringpassword){//获取主体对象Subjectsubject=SecurityUtils.getSubject();try{//自动调用CustomerRealm类中的身份验证方法subject.login(newUsernamePasswordToken(username,password));return"index";}catch(UnknownAccountExceptione){//接收异常并处理e.printStackTrace();model.addAttribute("msg","用户名有误,请重新登录");}catch(IncorrectCredentialsExceptione){//接收异常并处理e.printStackTrace();model.addAttribute("msg","密码有误,请重新登录");}return"login";}
1.2.6、shiro缓存配置
定义了shiro缓存,用户登录后,其用户信息、拥有的角色 / 权限不必每次去查,这样可以提高效率
默认缓存的配置
在 ShiroConfig中 的 getRealm() 方法中开启缓存管理
@BeanpublicRealmgetRealm(){CustomerRealmcustomerRealm=newCustomerRealm();//开启缓存管理customerRealm.setCacheManager(newEhCacheManager());//开启全局缓存customerRealm.setCachingEnabled(true);//开启认证缓存customerRealm.setAuthenticationCachingEnabled(true);customerRealm.setAuthenticationCacheName("authenticationCache");//开启权限缓存customerRealm.setAuthorizationCachingEnabled(true);customerRealm.setAuthorizationCacheName("authorizationCache");returncustomerRealm;}
与reids整合的缓存这里就不说明了,放在源码里自己查看,源码在下方
1.2.7、主页index.html的设置
在这里用标签来判断某些区域需要认证或什么角色或者什么权限才能访问
<!DOCTYPEhtml><htmlxmlns="http://www.w3.org/1999/xhtml"xmlns:th="http://www.thymeleaf.org"xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"><head><metacharset="UTF-8"><title>首页</title><linkrel="shortcuticon"href="#"></head><body><h1>index</h1><ahref="/logout">退出</a><div><ahref="/main">main</a>|<ahref="/manage">manage</a>|<ahref="/admin">admin</a></div><!--获取认证信息-->用户:<spanshiro:principal=""></span><hr><!--认证处理--><spanshiro:authenticated=""><hr>显示认证通过内容</span><spanshiro:notAuthenticated=""><hr>没有认证时显示</span><!--授权角色--><spanshiro:hasRole="admin"><hr>admin角色显示</span><spanshiro:hasPermission="user:*:*"><hr>具有用户模块的"user:*:*"权限显示</span></body></html>
1.3、简单测试
1.3.1、admin角色所有权限测试
1.3.2、无角色有权限测试
1.3.3、无角色无权限测试
到此,关于“SpringBoot怎么整合Shiro实现权限控制”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注恰卡编程网网站,小编会继续努力为大家带来更多实用的文章!
推荐阅读
-
springboot实现基于aop的切面日志
本文实例为大家分享了springboot实现基于aop的切面日志的具体代码,供大家参考,具体内容如下通过aop的切面方式实现日志...
-
SpringBoot定时任务功能怎么实现
-
SpringBoot中的@Import注解怎么使用
-
SpringBoot整合Lombok及常见问题怎么解决
-
springboot图片验证码功能模块怎么实现
-
Springboot+SpringSecurity怎么实现图片验证码登录
-
SpringBoot注解的知识点有哪些
SpringBoot注解的知识点有哪些这篇“SpringBoot注...
-
SpringBoot2.x中management.security.enabled=false无效怎么解决
-
springboot怎么禁用某项健康检查
springboot怎么禁用某项健康检查今天小编给大家分享一下sp...
-
SpringBoot2怎么自定义端点