shiro(详解)

编程入门 行业动态 更新时间:2024-10-24 18:15:47

shiro(<a href=https://www.elefans.com/category/jswz/34/1770044.html style=详解)"/>

shiro(详解)

这里写自定义目录标题

    • 什么是shiro
      • 什么是权限管理
      • 什么是身份认证
      • 什么是授权
      • Subject
      • SecurityManager
      • Authenticator
      • Authorizer
      • Realm
      • SessionManager
      • SessionDAO
      • CacheManager
      • Cryptography
      • `面试题`
      • 认证的开发
          • 1. 创建项目并引入依赖
          • 2. 引入shiro配置文件并加入如下配置
      • 自定义Realm
          • 自定义realm
          • 使用自定义Realm认证
      • 使用MD5和Salt
          • 1.自定义md5+salt的realm
          • 2.使用md5 + salt 认证
    • shiro中的授权
      • 授权
      • 关键对象
      • 权限字符串
      • shiro中授权编程实现方式
      • 开发授权
      • shiro中授权编程实现方式
          • 1.realm的实现
          • 2.授权
    • shiro架构
      • `面试题`
        • shiro核心组件:
    • Shiro和Spring Security比较
      • 2. Shiro 特点
      • `面试题`
        • 用户角色权限
    • 用户、角色及授权三者关系
    • springboot整合shiro的思路
    • 整合SpringBoot和shiro
      • 1 引入shiro jsp mybatis mysql druid shiro和ehcache 的依赖
      • 2 配置shiro环境
          • 1.配置shiroFilterFactoryBean
          • 2.配置WebSecurityManager
          • 3.创建自定义realm
          • 4.配置自定义realm
          • 5.编写控制器跳转至index.html
          • 6.启动springboot应用访问index
          • 7.加入权限控制
      • 5 常见过滤器
          • 1. 在login.jsp中开发认证界面
          • 2. 开发controller
          • 3.开发realm中返回静态数据(未连接数据库)
      • 7 退出认证
          • 1.开发controller
      • 8 MD5、Salt的认证实现
        • 1.开发数据库注册
          • 1.开发注册界面
          • 2配置application.properties配置文件
          • 2.创建entity
          • 3.创建DAO接口
          • 4.开发mapper配置文件
          • 5.开发service接口
          • 6.创建salt工具类
          • 7.开发service实现类
          • 8.开发Controller
        • 2.开发数据库认证
          • 0.开发DAO
          • 1.开发mapper配置文件
          • 2.开发Service接口
          • 3.开发Service实现类
          • 4.开发在工厂中获取bean对象的工具类
          • 5.修改自定义realm
          • 6.修改ShiroConfig中realm使用凭证匹配器以及hash散列
      • 6.8 授权实现
          • 0.页面资源授权
          • 1.代码方式授权
          • 2.方法调用授权
          • 4.创建dao方法
          • 5.mapper实现
          • 6.Service接口
          • 7.Service实现
          • 8.修改自定义realm
          • 9.启动测试
      • 6.9 使用CacheManager
        • 1.Cache 作用
        • 2.使用shiro中默认EhCache实现缓存
          • 1.开启缓存
  • 欢迎使用Markdown编辑器
    • 新的改变
    • 功能快捷键
    • 合理的创建标题,有助于目录的生成
    • 如何改变文本的样式
    • 插入链接与图片
    • 如何插入一段漂亮的代码片
    • 生成一个适合你的列表
    • 创建一个表格
      • 设定内容居中、居左、居右
      • SmartyPants
    • 创建一个自定义列表
    • 如何创建一个注脚
    • 注释也是必不可少的
    • KaTeX数学公式
    • 新的甘特图功能,丰富你的文章
    • UML 图表
    • FLowchart流程图
    • 导出与导入
      • 导出
      • 导入

生活不如意,快去敲# shiro

Apache旗下的一款安全权限框架

shiro可以完成:认证,加密,授权,会话管理,以及web集成,

什么是shiro

Shiro是apache旗下一个开源框架,它将软件系统的安全认证相关的功能抽取出来,实现用户身份认证,权限授权、加密、会话管理等功能,组成了一个通用的安全认证框架。

Apache Shiro 特性

Apache Shiro是一个全面的、蕴含丰富功能的安全框架

什么是权限管理

基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现`对用户访问系统的控制控制用户可以访问而且只能访问自己被授权的资源。

权限管理包括用户身份认证授权两部分,简称认证授权。对于需要访问控制的资源用户首先经过身份认证,认证通过后用户具有该资源的访问权限方可访问。

什么是身份认证

身份认证,就是判断一个用户是否为合法用户的处理过程。最常用的简单身份认证方式是系统通过核对用户输入的用户名和口令,看其是否与系统中存储的该用户的用户名和口令一致,来判断用户身份是否正确。

什么是授权

授权,即访问控制,控制谁能访问哪些资源。主体进行身份认证后需要分配权限方可访问系统的资源,对于某些资源没有权限是无法访问的

Subject

Subject即主体,外部应用与subject进行交互,subject记录了当前操作用户,将用户的概念理解为当前操作的主体,可能是一个通过浏览器请求的用户,也可能是一个运行的程序。外部程序通过subject进行认证,而subject是通过SecurityManager安全管理器进行认证授权

SecurityManager

SecurityManager即安全管理器,对全部的subject进行安全管理,它是shiro的核心,负责对所有的subject进行安全管理。通过SecurityManager可以完成subject的认证、授权等,实质上SecurityManager是通过Authenticator进行认证,通过Authorizer进行授权,通过SessionManager进行会话管理等。

Authenticator

Authenticator即认证器,对用户身份进行认证,Authenticator是一个接口,shiro提供ModularRealmAuthenticator实现类,通过ModularRealmAuthenticator基本上可以满足大多数需求,也可以自定义认证器。

Authorizer

Authorizer即授权器,用户通过认证器认证通过,在访问功能时需要通过授权器判断用户是否有此功能的操作权限。

Realm

Realm即领域,相当于datasource数据源,securityManager进行安全认证需要通过Realm获取用户权限数据,比如:如果用户身份数据在数据库那么realm就需要从数据库获取用户身份信息。

  • ​ 注意:不要把realm理解成只是从数据源取数据,在realm中还有认证授权校验的相关的代码。

SessionManager

sessionManager即会话管理,shiro框架定义了一套会话管理,它不依赖web容器的session,所以shiro可以使用在非web应用上,也可以将分布式应用的会话集中在一点管理,此特性可使它实现单点登录。

SessionDAO

SessionDAO即会话dao,是对session会话操作的一套接口,比如要将session存储到数据库,可以通过jdbc将会话存储到数据库。

CacheManager

CacheManager即缓存管理,将用户权限数据存储在缓存,这样可以提高性能。

Cryptography

Cryptography即密码管理,shiro提供了一套加密/解密的组件,方便开发。比如提供常用的散列、加/解密等功能。

面试题

1,Shiro可以做哪些工作?

Shiro可以帮助我们完成:认证、授权、加密、会话管理、与Web集成、缓存

shiro的核心架构

认证的开发

1. 创建项目并引入依赖
<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.5.3</version>
</dependency>
2. 引入shiro配置文件并加入如下配置
[users]
xiaochen=123
zhangsan=456
public class TestAuthenticator {public static void main(String[] args) {//创建securityManagerDefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();defaultSecurityManager.setRealm(new IniRealm("classpath:shiro.ini"));//将安装工具类中设置默认安全管理器SecurityUtils.setSecurityManager(defaultSecurityManager);//获取主体对象Subject subject = SecurityUtils.getSubject();//创建token令牌UsernamePasswordToken token = new UsernamePasswordToken("xiaochen", "123");try {subject.login(token);//用户登录System.out.println("登录成功~~");} catch (UnknownAccountException e) {e.printStackTrace();System.out.println("用户名错误!!");}catch (IncorrectCredentialsException e){e.printStackTrace();System.out.println("密码错误!!!");}}
}
  • 自定义Realm

    上边的程序使用的是Shiro自带的IniRealm,IniRealm从ini配置文件中读取用户的信息,大部分情况下需要从系统的数据库中读取用户信息,所以需要自定义realm。

    SimpleAccountRealm的部分源码中有两个方法一个是 认证 一个是 授权,

    自定义realm
    /*** 自定义realm*/
    public class CustomerRealm extends AuthorizingRealm {//授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {return null;}//认证方法@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {String principal = (String) token.getPrincipal();if("xiaochen".equals(principal)){return new SimpleAuthenticationInfo(principal,"123",this.getName());}return null;}
    }
    
    使用自定义Realm认证
    public class TestAuthenticatorCusttomerRealm {public static void main(String[] args) {//创建securityManagerDefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();//IniRealm realm = new IniRealm("classpath:shiro.ini");//设置为自定义realm获取认证数据defaultSecurityManager.setRealm(new CustomerRealm());//将安装工具类中设置默认安全管理器SecurityUtils.setSecurityManager(defaultSecurityManager);//获取主体对象Subject subject = SecurityUtils.getSubject();//创建token令牌UsernamePasswordToken token = new UsernamePasswordToken("xiaochen", "123");try {subject.login(token);//用户登录System.out.println("登录成功~~");} catch (UnknownAccountException e) {e.printStackTrace();System.out.println("用户名错误!!");}catch (IncorrectCredentialsException e){e.printStackTrace();System.out.println("密码错误!!!");}}
    }
    

    使用MD5和Salt

    实际应用是将盐和散列后的值存在数据库中,自动realm从数据库取出盐和加密后的值由shiro完成密码校验。

    1.自定义md5+salt的realm
    /*** 自定义md5+salt realm*/
    public class CustomerRealm extends AuthorizingRealm {//授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {return null;}//认证方法@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {String principal = (String) token.getPrincipal();if("xiaochen".equals(principal)){String password = "3c88b338102c1a343bcb88cd3878758e";String salt = "Q4F%";return new SimpleAuthenticationInfo(principal,password, ByteSource.Util.bytes(salt),this.getName());}return null;}
    
    2.使用md5 + salt 认证
    public class TestAuthenticatorCusttomerRealm {public static void main(String[] args) {//创建securityManagerDefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();//IniRealm realm = new IniRealm("classpath:shiro.ini");//设置为自定义realm获取认证数据CustomerRealm customerRealm = new CustomerRealm();//设置md5加密HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();credentialsMatcher.setHashAlgorithmName("MD5");credentialsMatcher.setHashIterations(1024);//设置散列次数customerRealm.setCredentialsMatcher(credentialsMatcher);defaultSecurityManager.setRealm(customerRealm);//将安装工具类中设置默认安全管理器SecurityUtils.setSecurityManager(defaultSecurityManager);//获取主体对象Subject subject = SecurityUtils.getSubject();//创建token令牌UsernamePasswordToken token = new UsernamePasswordToken("xiaochen", "123");try {subject.login(token);//用户登录System.out.println("登录成功~~");} catch (UnknownAccountException e) {e.printStackTrace();System.out.println("用户名错误!!");}catch (IncorrectCredentialsException e){e.printStackTrace();System.out.println("密码错误!!!");}}
    }
    

    shiro中的授权

    授权

    授权,即访问控制,控制谁能访问哪些资源。主体进行身份认证后需要分配权限方可访问系统的资源,对于某些资源没有权限是无法访问的。

    关键对象

    授权可简单理解为who对what(which)进行How操作:

    Who,即主体(Subject),主体需要访问系统中的资源。

    What,即资源(Resource),如系统菜单、页面、按钮、类方法、系统商品信息等。资源包括资源类型资源实例,比如商品信息为资源类型,类型为t01的商品为资源实例,编号为001的商品信息也属于资源实例。

    How,权限/许可(Permission),规定了主体对资源的操作许可,权限离开资源没有意义,如用户查询权限、用户添加权限、某个类方法的调用权限、编号为001用户的修改权限等,通过权限可知主体对哪些资源都有哪些操作许可。

    权限字符串

    ​ 权限字符串的规则是:资源标识符:操作:资源实例标识符,意思是对哪个资源的哪个实例具有什么操作,“:”是资源/操作/实例的分割符,权限字符串也可以使用*通配符。

    例子:

    • 用户创建权限:user:create,或user:create:*
    • 用户修改实例001的权限:user:update:001
    • 用户实例001的所有权限:user:*:001

    shiro中授权编程实现方式

    • 编程式

      Subject subject = SecurityUtils.getSubject();
      if(subject.hasRole(“admin”)) {//有权限
      } else {//无权限
      }
      
    • 注解式

      @RequiresRoles("admin")
      public void hello() {//有权限
      }
      
    • 标签式

      JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成:
      <shiro:hasRole name="admin"><!— 有权限—>
      </shiro:hasRole>
      注意: Thymeleaf 中使用shiro需要额外集成!
      

    开发授权

    shiro中授权编程实现方式

    • 编程式

      Subject subject = SecurityUtils.getSubject();
      if(subject.hasRole(“admin”)) {//有权限
      } else {//无权限
      }
      
    • 注解式

      @RequiresRoles("admin")
      public void hello() {//有权限
      }
      
    • 标签式

      JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成:
      <shiro:hasRole name="admin"><!— 有权限—>
      </shiro:hasRole>
      注意: Thymeleaf 中使用shiro需要额外集成!
      
    1.realm的实现
    public class CustomerMd5Realm1 extends AuthorizingRealm {//授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {System.out.println("========================");String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();System.out.println("身份信息:"+primaryPrincipal);//根据用户信息 用户名  获取当前用户角色信息,以及权限信息 xiaochen  admin userSimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();//将数据库中查询的角色信息赋值给全新对象simpleAuthorizationInfo.addRole("admin");simpleAuthorizationInfo.addRole("user");//将数据库中擦寻权限信息赋值给权限对象simpleAuthorizationInfo.addStringPermission("user:*:01");return simpleAuthorizationInfo;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {//获取身份信息String principal = (String) authenticationToken.getPrincipal();//根据用户名去数据库查找信息if ("xiaochen".equals(principal)){return new SimpleAuthenticationInfo(principal,"a3834da2205138a63d1c254361a7054a",ByteSource.Util.bytes("qwertyuiop"),this.getName());}return null;}
    }
    
    2.授权
    public class TestCustomerMD51 {public static void main(String[] args) {//创建安全管理器DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();//注入realmCustomerMd5Realm1 realm1 = new CustomerMd5Realm1();//设置realm使用hash凭证匹配器HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();//使用算法credentialsMatcher.setHashAlgorithmName("md5");//散列次数credentialsMatcher.setHashIterations(1024);realm1.setCredentialsMatcher(credentialsMatcher);defaultSecurityManager.setRealm(realm1);//全局工具类放到安全管理器中SecurityUtils.setSecurityManager(defaultSecurityManager);//主体 subjectSubject subject = SecurityUtils.getSubject();//创建令牌UsernamePasswordToken token = new UsernamePasswordToken("xiaochen","123");try {subject.login(token);System.out.println("认证状态"+subject.isPermittedAll());} catch (UnknownAccountException e) {e.printStackTrace();System.out.println("账号错误");} catch (IncorrectCredentialsException e){e.printStackTrace();System.out.println("密码错误");}//认证用户进行授权if(subject.isPermittedAll()){//1,基于角色的权限控制System.out.println(subject.hasRole("admin"));//2,基于多个角色System.out.println(subject.hasAllRoles(Arrays.asList("admin", "user")));//3基于多约束是否觉有其中一个角色boolean[] booleans = subject.hasRoles(Arrays.asList("admin", "user", "super"));for (boolean aBoolean : booleans) {System.out.println(aBoolean);}System.out.println("==========================");//基于权限字符串的访问控制  资源识别付  操作 资源类型System.out.println("权限"+subject.isPermitted("user:update:01"));}}
    }
    

shiro架构

核心

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IfMicglN-1624702127692)(C:\Users\曹雪峰\AppData\Roaming\Typora\typora-user-images\1620385643680.png)]

1.Shiro三个核心组件

Subject:主体,代表了当前 “用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都Subject,如网络爬虫,机器人等;即一个抽象概念;所有 Subject 都绑定到 SecurityManager,与 Subject 的所有交互都会委托给 SecurityManager;可以把 Subject 认为是一个门面;SecurityManager 才是实际的执行者;

SecurityManager:安全管理器;即所有与安全有关的操作都会与 SecurityManager 交互;且它管理着所有 Subject;可以看出它是 Shiro 的核心,它负责与后边介绍的其他组件进行交互,如果学习过 SpringMVC,你可以把它看成 DispatcherServlet 前端控制器;

Realm:域,Shiro 从 Realm 获取安全数据(如用户、角色、权限),就是说 SecurityManager 要验证用户身份,那么它需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色 / 权限进行验证用户是否能进行操作;可以把 Realm 看成 DataSource,即安全数据源。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ru7uMyor-1624702127693)(C:\Users\曹雪峰\AppData\Roaming\Typora\typora-user-images\1624281727814.png)]

面试题

Shiro工作流程

应用代码通过Subject来进行认证和授权,而Subject又委托给SecurityManager;

我们需要给Shiro的SecurityManager注入Realm,从而让SecurityManager能得到合法的用户及其权限进行判断。

shiro核心组件:

1、UsernamePasswordToken,Shiro 用来封装用户登录信息,使用用户的登录信息来创建令牌 Token,这里shiro会直接将密码和前面生成token中的密码进行匹配,如果匹配成功则登陆成功,不成功则报错

2、SecurityManager,Shiro 的核心部分,负责安全认证和授权。

3、Suject,Shiro 的一个抽象概念,包含了用户信息。

4、Realm,开发者自定义的模块,根据项目的需求,验证和授权的逻辑全部写在 Realm 中。

5、AuthenticationInfo,用户的角色信息集合,认证时使用。

6、AuthorzationInfo,角色的权限信息集合,授权时使用。

7、DefaultWebSecurityManager,安全管理器,开发者自定义的 Realm 需要注入到DefaultWebSecurityManager 进行管理才能生效。

8、ShiroFilterFactoryBean,过滤器工厂,Shiro 的基本运行机制是开发者定制规则,Shiro 去执行,具体的执行操作就是由 ShiroFilterFactoryBean 创建的一个个 Filter 对象来完成。

Shiro和Spring Security比较

Shiro比SpringSecurity更容易使用,实现和最重要的理解

Spring Security更加知名的唯一原因是因为品牌名称
“Spring”以简单而闻名,但讽刺的是很多人发现安装Spring Security很难

然而,Spring Security却有更好的社区支持
Apache Shiro在Spring Security处理密码学方面有一个额外的模块

Spring-security 对spring 结合较好,如果项目用的springmvc ,使用起来很方便。但是如果项目中没有用到spring,那就不要考虑它了。
Shiro 功能强大、且 简单、灵活。是Apache 下的项目比较可靠,且不跟任何的框架或者容器绑定,可以独立运行

2. Shiro 特点

(1)易于理解的 Java Security API;
(2)简单的身份认证(登录),支持多种数据源
(3)对角色的简单的签权(访问控制)
(4)支持一级缓存,以提升应用程序的性能;
(6)异构客户端会话访问;
(7)非常简单的加密 API;
(8)不跟任何的框架或者容器捆绑,可以独立运行

面试题

Apache Shiro 的三大核心组件:*

1、Subject :当前用户的操作

2、SecurityManager:用于管理所有的Subject

3、Realms:用于进行权限信息的验证

用户角色权限

用户、角色及授权三者关系

Shiro的授权模式采用Rbac模式,意思就是,谁,扮演了什么角色,被允许执行什么操作,其中的“谁”就是user,其中扮演什么角色(role),操作就是权限(permission);

RBAC 认为授权实际上是WhoWhatHow 三元组之间的关系,也就是WhoWhat 进行How 的操作,也就是“主体”对“客体”的操作。

Who:是权限的拥有者或主体(如:User,Role)。

What:是操作或对象(operation,object)。**

How:具体的权限(Privilege,正向授权与负向授权)

springboot整合shiro的思路

整合SpringBoot和shiro

1 引入shiro jsp mybatis mysql druid shiro和ehcache 的依赖

<!--引入jsp解析依赖--><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId></dependency><dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><!--引入shiro整合springboot依赖--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-starter</artifactId><version>1.5.3</version></dependency><!--引入mybatis--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.38</version></dependency><!--druid--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.19</version></dependency><!--引入shiro和ehcache--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-ehcache</artifactId><version>1.5.3</version></dependency>

2 配置shiro环境

1.配置shiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager){//创建shiro的filterShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();//注入安全管理器shiroFilterFactoryBean.setSecurityManager(securityManager);return shiroFilterFactoryBean;
}
2.配置WebSecurityManager
@Bean
public DefaultWebSecurityManager getSecurityManager(Realm realm){DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();defaultWebSecurityManager.setRealm(realm);return defaultWebSecurityManager;
}
3.创建自定义realm
public class CustomerRealm extends AuthorizingRealm {//处理授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {return null;}//处理认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {return null;}
}
4.配置自定义realm
//创建自定义realm
@Bean
public Realm getRealm(){return new CustomerRealm();
}
5.编写控制器跳转至index.html
@Controller
public class IndexController {@RequestMapping("index")public String index(){System.out.println("跳转至主页");return "index";}
}
6.启动springboot应用访问index
  • 注意:
    • 默认在配置好shiro环境后默认环境中没有对项目中任何资源进行权限控制,所有现在项目中所有资源都可以通过路径访问
7.加入权限控制
  • 修改ShiroFilterFactoryBean配置

    //注入安全管理器
    shiroFilterFactoryBean.setSecurityManager(securityManager);
    Map<String,String> map =  new LinkedHashMap<>();
    map.put("/**","authc");
    //配置认证和授权规则
    shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
    
    • /** 代表拦截项目中一切资源 authc 代表shiro中的一个filter的别名,详细内容看文档的shirofilter列表

5 常见过滤器

  • 注意: shiro提供和多个默认的过滤器,我们可以用这些过滤器来配置控制指定url的权限:
Filter解释
anon无参,开放权限,可以理解为匿名用户或游客
authc无参,需要认证
logout无参,注销,执行后会直接跳转到shiroFilterFactoryBean.setLoginUrl(); 也就是退出
authcBasic无参,表示 httpBasic 认证
user无参,表示必须存在用户,当登入操作时不做检查
ssl无参,表示安全的URL请求,协议为 https
perms[user]参数可写多个,表示需要某个或某些权限才能通过,多个参数时写 perms[“user, admin”],当有多个参数时必须每个参数都通过才算通过
roles[user]参数可写多个,表示是某个或某些角色才能通过,多个参数时写 roles[“admin,user”],当有多个参数时必须每个参数都通过才算通过
rest[user]根据请求的方法,相当于 perms[user:method],其中 method 为 post,get,delete 等
port[8081]当请求的URL端口不是8081时,跳转到schemal://serverName:8081?queryString 其中 schmal 是协议 http 或 https 等等,serverName 是你访问的 Host,8081 是 Port 端口,queryString 是你访问的 URL 里的 ? 后面的参数

1. 在login.jsp中开发认证界面
<form action="${pageContext.request.contextPath}/user/login" method="post">用户名:<input type="text" name="username" > <br/>密码  : <input type="text" name="password"> <br><input type="submit" value="登录">
</form>
2. 开发controller
@Controller
@RequestMapping("user")
public class UserController {/*** 用来处理身份认证* @param username* @param password* @return*/@RequestMapping("login")public String login(String username,String password){//获取主体对象Subject subject = SecurityUtils.getSubject();try {subject.login(new UsernamePasswordToken(username,password));return  "redirect:/index.jsp";} catch (UnknownAccountException e) {e.printStackTrace();System.out.println("用户名错误!");}catch (IncorrectCredentialsException e){e.printStackTrace();System.out.println("密码错误!");}return "redirect:/login.jsp";}
}
  • 在认证过程中使用subject.login进行认证
3.开发realm中返回静态数据(未连接数据库)
@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {System.out.println("==========================");String principal = (String) token.getPrincipal();if("xiaochen".equals(principal)){return new SimpleAuthenticationInfo(principal,"123",this.getName());}return null;}
}
  • 认证功能没有md5和随机盐的认证就实现啦

7 退出认证

1.开发controller
@Controller
@RequestMapping("user")
public class UserController {/*** 退出登录**/@RequestMapping("logout")public String logout(){Subject subject = SecurityUtils.getSubject();subject.logout();//退出用户return "redirect:/login.jsp";}
}

8 MD5、Salt的认证实现

1.开发数据库注册

1.开发注册界面
<h1>用户注册</h1>
<form action="${pageContext.request.contextPath}/user/register" method="post">用户名:<input type="text" name="username" > <br/>密码  : <input type="text" name="password"> <br><input type="submit" value="立即注册">
</form>
2配置application.properties配置文件
server.port=8888
server.servlet.context-path=/shiro
spring.application.name=shirospring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
#新增配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/shiro?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=rootmybatis.type-aliases-package=com.baizhi.springboot_jsp_shiro.entity
mybatis.mapper-locations=classpath:com/baizhi/mapper/*.xml
2.创建entity
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class User {private String  id;private String username;private String password;private String salt;
}
3.创建DAO接口
@Mapper
public interface UserDAO {void save(User user);
}
4.开发mapper配置文件
<insert id="save" parameterType="com.xhizhi.entity.User" useGeneratedKeys="true" keyProperty="id">insert into user(id,username,password,selt) values(#{id},#{username},#{password},#{selt})</insert>
5.开发service接口
public interface UserService {//注册用户方法void register(User user);
}
6.创建salt工具类
public class SaltUtils {/*** 生成salt的静态方法* @param n* @return*/public static String getSalt(int n){char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890!@#$%^&*()".toCharArray();StringBuilder sb = new StringBuilder();for (int i = 0; i < n; i++) {char aChar = chars[new Random().nextInt(chars.length)];sb.append(aChar);}return sb.toString();}
}
7.开发service实现类
@Service
@Transactional
public class UserServiceImpl implements UserService {@Autowiredprivate UserDAO userDAO;@Overridepublic void register(User user) {//处理业务调用dao//1.生成随机盐String salt = SaltUtils.getSalt(8);//2.将随机盐保存到数据user.setSalt(salt);//3.明文密码进行md5 + salt + hash散列Md5Hash md5Hash = new Md5Hash(user.getPassword(),salt,1024);user.setPassword(md5Hash.toHex());userDAO.save(user);}
}
8.开发Controller
@Controller
@RequestMapping("user")
public class UserController {@Autowiredprivate UserService userService;/*** 用户注册*/@RequestMapping("register")public String register(User user) {try {userService.register(user);return "redirect:/login.jsp";}catch (Exception e){e.printStackTrace();return "redirect:/register.jsp";}}
}

2.开发数据库认证

0.开发DAO
@Mapper
public interface UserDAO {void save(User user);//根据身份信息认证的方法User findByUserName(String username);
}
1.开发mapper配置文件
<select id="findByUserName" parameterType="String" resultType="User">select id,username,password,selt from userwhere username = #{username}</select>
2.开发Service接口
public interface UserService {//注册用户方法void register(User user);//根据用户名查询业务的方法User findByUserName(String username);
}
3.开发Service实现类
@Service("userService")
@Transactional
public class UserServiceImpl implements UserService {@Autowiredprivate UserDAO userDAO;@Overridepublic User findByUserName(String username) {return userDAO.findByUserName(username);}
}
4.开发在工厂中获取bean对象的工具类
@Component
public class ApplicationContextUtils implements ApplicationContextAware {private static ApplicationContext context;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.context = applicationContext;}//根据bean名字获取工厂中指定bean 对象public static Object getBean(String beanName){return context.getBean(beanName);}
}
5.修改自定义realm
 @Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {System.out.println("==========================");//根据身份信息String principal = (String) token.getPrincipal();//在工厂中获取service对象UserService userService = (UserService) ApplicationContextUtils.getBean("userService");//根据身份信息查询User user = userService.findByUserName(principal);if(!ObjectUtils.isEmpty(user)){//返回数据库信息return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(), ByteSource.Util.bytes(user.getSalt()),this.getName());}return null;}
6.修改ShiroConfig中realm使用凭证匹配器以及hash散列
@Bean
public Realm getRealm(){CustomerRealm customerRealm = new CustomerRealm();//设置hashed凭证匹配器HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();//设置md5加密credentialsMatcher.setHashAlgorithmName("md5");//设置散列次数credentialsMatcher.setHashIterations(1024);customerRealm.setCredentialsMatcher(credentialsMatcher);return customerRealm;
}

6.8 授权实现

0.页面资源授权
<%@taglib prefix="shiro" uri="" %><shiro:hasAnyRoles name="user,admin"><li><a href="">用户管理</a><ul><shiro:hasPermission name="user:add:*"><li><a href="">添加</a></li></shiro:hasPermission><shiro:hasPermission name="user:delete:*"><li><a href="">删除</a></li></shiro:hasPermission><shiro:hasPermission name="user:update:*"><li><a href="">修改</a></li></shiro:hasPermission><shiro:hasPermission name="user:find:*"><li><a href="">查询</a></li></shiro:hasPermission></ul></li></shiro:hasAnyRoles><shiro:hasRole name="admin"><li><a href="">商品管理</a></li><li><a href="">订单管理</a></li><li><a href="">物流管理</a></li></shiro:hasRole>
1.代码方式授权
@RequestMapping("save")
public String save(){System.out.println("进入方法");//获取主体对象Subject subject = SecurityUtils.getSubject();//代码方式if (subject.hasRole("admin")) {System.out.println("保存订单!");}else{System.out.println("无权访问!");}//基于权限字符串//....return "redirect:/index.jsp";
}
2.方法调用授权
  • @RequiresRoles 用来基于角色进行授权
  • @RequiresPermissions 用来基于权限进行授权
@RequiresRoles(value={"admin","user"})//用来判断角色  同时具有 admin user
@RequiresPermissions("user:update:01") //用来判断权限字符串
@RequestMapping("save")
public String save(){System.out.println("进入方法");return "redirect:/index.jsp";
}
4.创建dao方法
 //根据用户名查询所有角色
User findRolesByUserName(String username);
//根据角色id查询权限集合
List<Perms> findPermsByRoleId(String id);
5.mapper实现
<resultMap id="userMap" type="User"><id column="uid" property="id"/><result column="username" property="username"/><!--角色信息--><collection property="roles" javaType="list" ofType="Role"><id column="id" property="id"/><result column="rname" property="name"/></collection></resultMap><select id="findRolesName" parameterType="String" resultMap="userMap">SELECT u.id uid,u.username,r.id,r.name rnameFROM user uLEFT JOIN user_role urON u.id = ur.useridLEFT JOIN role rON ur.roleid = r.idWHERE u.username=#{username}</select><select id="findPermsByRoleId" parameterType="String" resultType="Perms">SELECT p.id,p.name,p.url,r.name FROM role rLEFT JOIN role_perms rpON r.id = rp.roleidLEFT JOIN perms pON rp.prmsid = p.idWHERE r.id=#{id}</select>
6.Service接口
//根据用户名查询所有角色
User findRolesByUserName(String username);
//根据角色id查询权限集合
List<Perms> findPermsByRoleId(String id);
7.Service实现
@Override
public List<Perms> findPermsByRoleId(String id) {return userDAO.findPermsByRoleId(id);
}@Override
public User findRolesByUserName(String username) {return userDAO.findRolesByUserName(username);
}
8.修改自定义realm
public class CustomerRealm extends AuthorizingRealm {@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {//获取身份信息String primaryPrincipal = (String) principals.getPrimaryPrincipal();System.out.println("调用授权验证: "+primaryPrincipal);//根据主身份信息获取角色 和 权限信息UserService userService = (UserService) ApplicationContextUtils.getBean("userService");User user = userService.findRolesByUserName(primaryPrincipal);//授权角色信息if(!CollectionUtils.isEmpty(user.getRoles())){SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();user.getRoles().forEach(role->{simpleAuthorizationInfo.addRole(role.getName());//权限信息List<Perms> perms = userService.findPermsByRoleId(role.getId());if(!CollectionUtils.isEmpty(perms)){perms.forEach(perm->{simpleAuthorizationInfo.addStringPermission(perm.getName());});}});return simpleAuthorizationInfo;}return null;}
}
9.启动测试

6.9 使用CacheManager

1.Cache 作用

  • Cache 缓存: 计算机内存中一段数据
  • 作用: 用来减轻DB的访问压力,从而提高系统的查询效率
  • 流程:

2.使用shiro中默认EhCache实现缓存

1.开启缓存
//3.创建自定义realm@Beanpublic Realm getRealm(){CustomerRealm customerRealm = new CustomerRealm();//修改凭证校验匹配器HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();//设置加密算法为md5credentialsMatcher.setHashAlgorithmName("MD5");//设置散列次数credentialsMatcher.setHashIterations(1024);customerRealm.setCredentialsMatcher(credentialsMatcher);//开启缓存管理器customerRealm.setCachingEnabled(true);customerRealm.setAuthorizationCachingEnabled(true);customerRealm.setAuthorizationCachingEnabled(true);customerRealm.setCacheManager(new EhCacheManager());return customerRealm;}

代码

欢迎使用Markdown编辑器

你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

新的改变

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 全新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法1 功能;
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能。

功能快捷键

撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G

合理的创建标题,有助于目录的生成

直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

如何改变文本的样式

强调文本 强调文本

加粗文本 加粗文本

标记文本

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

插入链接与图片

链接: link.

图片:

带尺寸的图片:

居中的图片:

居中并且带尺寸的图片:

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block
var foo = 'bar';

生成一个适合你的列表

  • 项目
    • 项目
      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目Value
电脑$1600
手机$12
导管$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列第二列第三列
第一列文本居中第二列文本居右第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPEASCIIHTML
Single backticks'Isn't this fun?'‘Isn’t this fun?’
Quotes"Isn't this fun?"“Isn’t this fun?”
Dashes-- is en-dash, --- is em-dash– is en-dash, — is em-dash

创建一个自定义列表

Markdown
Text-to- HTML conversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。2

注释也是必不可少的

Markdown将文本转换为 HTML。

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n−1)!∀n∈N 是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=∫0∞​tz−1e−tdt.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图:

张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

这将产生一个流程图。:

链接 长方形 圆角长方形 菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

Created with Raphaël 2.3.0 开始 我的操作 确认? 结束 yes no
  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. mermaid语法说明 ↩︎

  2. 注脚的解释 ↩︎

更多推荐

shiro(详解)

本文发布于:2023-06-18 23:15:57,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/777193.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:详解   shiro

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!