Shiro+SpringBoot权限实战:认证授权缓存全搞定目录1.shiro的相关概念——核心框架2.springboot整合shiro环境搭建2.1.springboot的创建2.2. 引入thymeleaf模板3.shiro中的认证和授权3.1 认证开发3.2 自定义Realm1.shiro提供的Realm2.根据认证源码认证使用的是SimpleAccountRealm3.3.使用MD5+Salt+Hash1.自定义md5+salt的realm2.使用md5+salt 认证4 .shiro中的授权4.1授权的相关概念4.2shiro编程实现方式1.realm的实现4.整合SpringBoot项目实战4.1 整合思路4.2配置环境4.3常见的过滤器4.4 认证功能和退出的实现4.5MD5、Salt的认证实现4.6权限的实现1.页面资源授权2.代码方式授权3.方法调用授权4.授权数据持久化5.创建实体类6.创建dao方法7.mapper实现8.Service接口9.Service实现10.修改自定义realm5.使用CacheManager5.1使用shiro中默认EhCache实现缓存6、Shiro整合springboot的redis实现6.1 写ShiroCacheManager实现类6.2 ShiroCache真正的缓存实现类6.3 ByteSource的实现类6.4 对CustomerRealm中的ByteSource进行替换7.Shiro整合springboot之thymeleaf权限控制1.引入扩展依赖2.常见权限控制标签使用4.加入shiro的方言配置1.shiro的相关概念——核心框架Subject :为主体信息,访问的用户或者运行的程序SecurityManager即安全管理器,对全部的subject进行安全管理。同时:SecurityManager是一个接口,继承了Authenticator, Authorizer, SessionManager这三个接口。Authenticator即认证器Authorizer即授权器Realm即领域,相当于datasource数据源,securityManager进行安全认证需要通过Realm获取用户权限数据sessionManager即会话管理2.springboot整合shiro环境搭建1.springboot的创建1.右击文件名进入module中选择spring Initializr最后选择spring web2. 引入thymeleaf模板详细文档:[[(62条消息) Thymeleaf模板引擎详细介绍_AE86-打破常规的博客-CSDN博客_thymeleaf模板引擎!--thymeleaf模板--dependencygroupIdorg.thymeleaf/groupIdartifactIdthymeleaf-spring5/artifactId/dependencydependencygroupIdorg.thymeleaf.extras/groupIdartifactIdthymeleaf-extras-java8time/artifactId/dependencyThymeleaf简单表达式:变量表达式: ${…}选择变量表达式: *{…}消息表达式: #{…}链接网址表达式: @{…}片段表达式: ~{…}示例代码:spanth:text="${book.author.name}":获取name这个变量的值赋值给text ...spanth:text="*{title}".../spanspanth:text="*{price}".../spanath:href="@{user/index}"/a/div3.shiro中的认证和授权认证流程3.1 认证开发1.引入jar包dependencygroupIdorg.apache.shiro/groupIdartifactIdshiro-core/artifactIdversion1.5.3/version/dependency2.引入shiro配置文件配置文件:名称随意,以 .ini 结尾,放在 resources 目录下[users] zhangsan=123456 lisi=456789 huang=ming开发认证代码packagecom.huang.config;importorg.apache.shiro.SecurityUtils;importorg.apache.shiro.authc.IncorrectCredentialsException;importorg.apache.shiro.authc.UnknownAccountException;importorg.apache.shiro.authc.UsernamePasswordToken;importorg.apache.shiro.mgt.DefaultSecurityManager;importorg.apache.shiro.realm.text.IniRealm;importorg.apache.shiro.subject.Subject;/** * @author * @version 1.0 */publicclassmyShiroConfig{publicstaticvoidmain(String[]args){//1.创建安全管理器对象DefaultSecurityManagersecurityManager=newDefaultSecurityManager();//2.给安全管理器设置realmsecurityManager.setRealm(newIniRealm("classpath:shiro.ini"));//3.SecurityUtils给全局安全工具类设置安全管理器SecurityUtils.setSecurityManager(securityManager);//4.关键对象subject主体Subjectsubject=SecurityUtils.getSubject();//5.创建令牌UsernamePasswordTokentoken=newUsernamePasswordToken("huang","xing");//6.登入认证try{subject.login(token);System.out.println("认证成功");}catch(UnknownAccountExceptione){System.out.println("用户名错误");}catch(IncorrectCredentialsExceptione){System.out.println("密码错误");}}}4.常见的异常类型DisabledAccountException(帐号被禁用)LockedAccountException(帐号被锁定)ExcessiveAttemptsException(登录失败次数过多)ExpiredCredentialsException(凭证过期)等3.2 自定义Realm认证:1.最终执行用户名比较是 在SimpleAccountRealm类 的 doGetAuthenticationInfo 方法中完成用户名校验2.最终密码校验是在AuthenticatingRealm类 的 assertCredentialsMatch方法 中总结:AuthenticatingRealm认证:realm doGetAuthenticationInfAuthorizingRealm授权:realm doGetAuthorizationInfo1.shiro提供的Realm2.根据认证源码认证使用的是SimpleAccountRealm自定义reaml代码:packagecom.huang.config.Reaml;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.realm.AuthorizingRealm;importorg.apache.shiro.realm.SimpleAccountRealm;importorg.apache.shiro.subject.PrincipalCollection;/** * @author * @version 1.0 */publicclassTestRemlextendsAuthorizingRealm{@Override//授权protectedAuthorizationInfodoGetAuthorizationInfo(PrincipalCollectionprincipalCollection){returnnull;}@Override//认证protectedAuthenticationInfodoGetAuthenticationInfo(AuthenticationTokenauthenticationToken)throwsAuthenticationException{//获取用户名Stringprincipal=(String)authenticationToken.getPrincipal();//假设username,password是从数据库获得的信息Stringusername="huang";Stringpassword="123456";if(username.equals(principal)){//参数1:返回数据库中正确的用户名//参数2:返回数据库中正确密码//参数3:提供当前realm的名字 this.getName();SimpleAuthenticationInfoinfo=newSimpleAuthenticationInfo(username,password,this.getName());returninfo;}returnnull;}}3.3.使用MD5+Salt+Hash作用:一般用来加密或者签名(校验和)特点:MD5算法不可逆如何内容相同无论执行多少次md5生成结果始终是一致网络上提供的MD5在线解密一般是用穷举的方法生成结果:始终是一个16进制32位长度字符串MD5的基本使用packagecom.lut.test;importorg.apache.shiro.crypto.hash.Md5Hash;publicclassTestShiroMD5{publicstaticvoidmain(String[]args){//使用md5Md5Hashmd5Hash=newMd5Hash("123");System.out.println(md5Hash.toHex());//使用MD5 + salt处理Md5Hashmd5Hash1=newMd5Hash("123","X0*7ps");System.out.println(md5Hash1.toHex());//使用md5 + salt + hash散列(参数代表要散列多少次,一般是 1024或2048)Md5Hashmd5Hash2=newMd5Hash("123","X0*7ps",1024);System.out.println(md5Hash2.toHex());}}1.自定义md5+salt的realmpackagecom.huang.config.Reaml;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.realm.AuthorizingRealm;importorg.apache.shiro.subject.PrincipalCollection;importorg.apache.shiro.util.ByteSource;/** * @author * @version 1.0 */publicclassMd5ReamlextendsAuthorizingRealm{@OverrideprotectedAuthorizationInfodoGetAuthorizationInfo(PrincipalCollectionprincipalCollection){returnnull;}@OverrideprotectedAuthenticationInfodoGetAuthenticationInfo(AuthenticationTokenauthenticationToken)throwsAuthenticationException{Stringprincipal=(String)authenticationToken.getPrincipal();//参数1:数据库用户名//参数2:数据库md5+salt之后的密码//参数3:注册时的随机盐//参数4:realm的名字returnnewSimpleAuthenticationInfo(principal,"a60bb2103d1d2f64653a446700165584",ByteSource.Util.bytes("es@fe24"),this.getName());}}2.使用md5+salt 认证packagecom.huang.config;importcom.huang.config.Reaml.Md5Reaml;importorg.apache.shiro.SecurityUtils;importorg.apache.shiro.authc.*;importorg.apache.shiro.authc.credential.CredentialsMatcher;importorg.apache.shiro.authc.credential.HashedCredentialsMatcher;importorg.apache.shiro.mgt.DefaultSecurityManager;importorg.apache.shiro.subject.Subject;/** * @author * @version 1.0 */publicclassMd5ReamlTest{publicstaticvoidmain(String[]args){//设置安全管理器DefaultSecurityManagersecurityManager=newDefaultSecurityManager();//给安全管理器设置reamlMd5Reamlmd5Reaml=newMd5Reaml();//设置md5加密HashedCredentialsMatcherhashedCredentialsMatcher=newHashedCredentialsMatcher("md5");//迭代1024次hashedCredentialsMatcher.setHashIterations(1024);//给reaml设计密码匹配器md5Reaml.setCredentialsMatcher(hashedCredentialsMatcher);securityManager.setRealm(md5Reaml);//把安全管理器交给安全管理器工具类SecurityUtils.setSecurityManager(securityManager);//获取用户Subjectsubject=SecurityUtils.getSubject();UsernamePasswordTokentoken=newUsernamePasswordToken("huang","xing");try{subject.login(token);System.out.println("登入成功");}catch(UnknownAccountExceptione){e.printStackTrace();System.out.println("用户名错误");}catch(IncorrectCredentialsExceptione){e.printStackTrace();System.out.println("密码错误");}}}4 .shiro中的授权4.1授权的相关概念授权流程基于角色的访问控制RBAC基于角色的访问控制(Role-Based Access Control)是以角色为中心进行访问控制if(subject.hasRole("admin")){//操作什么资源}基于资源的访问RBAC基于资源的访问控制(Resource-Based Access Control)是以资源为中心进行访问控制if(subject.isPermission("user:update:01")){//资源实例//对资源01用户具有修改的权限}if(subject.isPermission("user:update:*")){//资源类型//对 所有的资源 用户具有更新的权限}授权的字符串:用户创建权限:user:create,或user:create:*用户修改实例001的权限:user:update:001用户实例001的所有权限:user: *:0014.2shiro编程实现方式编程式Subjectsubject=SecurityUtils.getSubject();if(subject.hasRole(“admin”)){//有权限}else{//无权限}注解式@RequiresRoles("admin")publicvoidhello(){//有权限}1.realm的实现packagecom.huang.config.Reaml;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.ByteSource;/** * @author * @version 1.0 */publicclassMd5ReamlextendsAuthorizingRealm{@OverrideprotectedAuthorizationInfodoGetAuthorizationInfo(PrincipalCollectionprincipalCollection){//得到用户名Stringprincipal=(String)principalCollection.getPrimaryPrincipal();//根据身份信息 用户名 获取当前用户的角色信息,以及权限信息SimpleAuthorizationInfosimpleAuthorizationInfo=newSimpleAuthorizationInfo();//假设 admin,user 是从数据库查到的 角色信息simpleAuthorizationInfo.addRole("author");simpleAuthorizationInfo.addRole("user");//假设 ... 是从数据库查到的 权限信息赋值给权限对象simpleAuthorizationInfo.addStringPermission("user:*:01");simpleAuthorizationInfo.addStringPermission("user:delete:*");returnsimpleAuthorizationInfo;}@OverrideprotectedAuthenticationInfodoGetAuthenticationInfo(AuthenticationTokenauthenticationToken)throwsAuthenticationException{Stringprincipal=(String)authenticationToken.getPrincipal();//参数1:数据库用户名//参数2:数据库md5+salt之后的密码//参数3:注册时的随机盐//参数4:realm的名字returnnewSimpleAuthenticationInfo(principal,"a60bb2103d1d2f64653a446700165584",ByteSource.Util.bytes("es@fe24"),this.getName());}}授权逻辑代码实现:packagecom.huang.config;import