1. 权限管理

1.1 什么是权限管理?

权限管理实现对用户访问系统的控制,按照安全规则或者安全策略,可以控制用户只能访问自己被授权的资源

权限管理包括用户身份认证和授权两部分,简称认证授权

1.2 什么是身份认证?

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

1.3 什么是授权?

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

2. 什么是 shiro?

shiro 是一个功能强大且易于使用的 Java 安全框架,能够完成身份认证、授权、加密和会话管理等功能

2.1 shiro 的核心架构

  • Subject

    主体,外部应用与 subject 进行交互,subject 记录了当前操作用户,将用户的概念理解为当前操作的主体,可能是一个通过浏览器请求的用户,也可能是一个运行的程序。Subject 在 shiro 中是一个接口,接口中定义了很多认证授相关的方法,外部程序通过 subject 进行认证授,而 subject 是通过 SecurityManager 安全管理器进行认证授权

  • SecurityManager

    安全管理器,对全部的 subject 进行安全管理,是 shiro 的核心。通过 SecurityManager 可以完成 subject 的认证、授权等,实质上 SecurityManager 是通过 Authenticator 进行认证,通过 Authorizer 进行授权,通过 SessionManager 进行会话管理。SecurityManager 是一个接口,继承了 Authenticator,Authorizer,SessionManager 这三个接口

  • Authenticator

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

  • Authorizer

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

  • Realm

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

  • SessionManager

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

  • SessionDAO

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

  • CacheManager

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

  • Cryptography

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

3. shiro 中的认证

3.1 认证

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

3.2 shiro 认证中的关键对象

  • Subject:主体

    访问系统的用户,主体可以是用户、程序等,进行认证的都称为主体

  • Principal:身份信息

    是主体(subject)进行身份认证的标识,标识必须具有唯一性, 如用户名、手机号、邮箱地址等,一个主体可以有多个身份,但是必须有一个主身份(Primary Principal)

  • credential:凭证信息

    是只有主体自己知道的安全信息,如密码、证书等

3.3 认证流程

3.4 认证开发

3.4.1 引入依赖

  1. <dependency>
  2. <groupId>org.apache.shiro</groupId>
  3. <artifactId>shiro-core</artifactId>
  4. <version>1.5.3</version>
  5. </dependency>

3.4.2 创建配置文件

该配置文件用来书写系统中相关的权限数据,主要用于学习使用

  1. [users]
  2. xiaochen=123
  3. zhangsan=456

3.4.3 开发认证代码

  1. public class TestAuthenticator {
  2. public static void main(String[] args) {
  3. // 1.创建安全管理器对象
  4. DefaultSecurityManager securityManager = new DefaultSecurityManager();
  5. // 2.给安全管理器设置 realm
  6. securityManager.setRealm(new IniRealm("classpath:shiro.ini"));
  7. // 3.给 SecurityUtils 全局安全工具类设置安全管理器
  8. SecurityUtils.setSecurityManager(securityManager);
  9. // 4.获取认证主体
  10. Subject subject = SecurityUtils.getSubject();
  11. // 5.创建令牌
  12. UsernamePasswordToken token = new UsernamePasswordToken("xiaochen", "123");
  13. // 6.认证
  14. try {
  15. System.out.println("认证状态:" + subject.isAuthenticated());
  16. subject.login(token);
  17. System.out.println("认证状态:" + subject.isAuthenticated());
  18. } catch (Exception e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. }

3.5 自定义 Realm

自定义 Realm 的实现,即是将认证/授权数据来源转为数据库的实现

  1. public class TestCustomerRealmAuthenticator {
  2. public static void main(String[] args) {
  3. // 1.创建安全管理器对象
  4. DefaultSecurityManager securityManager = new DefaultSecurityManager();
  5. // 2.设置自定义realm
  6. securityManager.setRealm(new CustomerRealm());
  7. // 3.给 SecurityUtils 全局安全工具类设置安全管理器
  8. SecurityUtils.setSecurityManager(securityManager);
  9. // 4.获取认证主体
  10. Subject subject = SecurityUtils.getSubject();
  11. // 5.创建令牌
  12. UsernamePasswordToken token = new UsernamePasswordToken("xiaochen", "123");
  13. // 6.认证
  14. try {
  15. System.out.println("认证状态:" + subject.isAuthenticated());
  16. subject.login(token);
  17. System.out.println("认证状态:" + subject.isAuthenticated());
  18. } catch (Exception e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. }

自定义 Realm 代码实现

  1. public class CustomerRealm extends AuthorizingRealm {
  2. // 授权
  3. @Override
  4. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
  5. return null;
  6. }
  7. // 认证
  8. @Override
  9. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
  10. // 1. 在token中获取用户名
  11. String principal = (String) authenticationToken.getPrincipal();
  12. // 2. 查询数据库,此处模拟数据库数据
  13. if ("xiaochen".equals(principal)) {
  14. // 参数1:正确的用户名
  15. // 参数2:正确的密码
  16. // 参数3:提供当前realm的名字
  17. SimpleAuthenticationInfo simpleAuthenticationInfo
  18. = new SimpleAuthenticationInfo("xianchen", "123", this.getName());
  19. return simpleAuthenticationInfo;
  20. }
  21. return null;
  22. }
  23. }

3.6 明文加密

实际使用时,我们不可能把用户密码以明文形式显示,需要做加密处理

通常的加密方式是使用 md5 + salt + hash 散列的形式,校验过程:保存盐和散列后的值,在 shiro 完成密码校验

下面是使用 shiro 提供的 api 完成加密代码示例

  1. public class TestShiroMD5 {
  2. public static void main(String[] args) {
  3. // 1. 使用md5加密
  4. // 参数1是明文密码
  5. Md5Hash md5Hash1 = new Md5Hash("123");
  6. // 打印加密后的密文
  7. // 结果:202cb962ac59075b964b07152d234b70
  8. System.out.println(md5Hash1.toHex());
  9. // 2. 使用md5+salt加密
  10. Md5Hash md5Hash2 = new Md5Hash("123", "X0*7ps");
  11. // 8a83592a02263bfe6752b2b5b03a4799
  12. System.out.println(md5Hash2.toHex());
  13. // 3. 使用md5+salt+hash散列加密
  14. Md5Hash md5Hash3 = new Md5Hash("123", "X0*7ps", 1024);
  15. // e4f9bf3e0c58f045e62c23c533fcf633
  16. System.out.println(md5Hash3.toHex());
  17. }
  18. }

自定义 CustomerMd5Realm

  1. public class CustomerMd5Realm extends AuthorizingRealm {
  2. // 授权
  3. @Override
  4. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
  5. return null;
  6. }
  7. // 认证
  8. @Override
  9. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
  10. // 1. 在token中获取用户名
  11. String principal = (String) authenticationToken.getPrincipal();
  12. // 2. 查询数据库,此处模拟数据库数据
  13. if ("xiaochen".equals(principal)) {
  14. // 参数1:正确的用户名
  15. // 参数2:正确的密码
  16. // 参数3:提供当前realm的名字
  17. // md5
  18. // return new SimpleAuthenticationInfo(principal, "202cb962ac59075b964b07152d234b70", this.getName());
  19. // md5+salt
  20. /*return new SimpleAuthenticationInfo(principal, "8a83592a02263bfe6752b2b5b03a4799", ByteSource.Util.bytes("X0*7ps"), this.getName());*/
  21. }
  22. return null;
  23. }
  24. }

校验流程

  1. public class TestCustomerMd5RealmAuthenticator {
  2. public static void main(String[] args) {
  3. // 1.创建安全管理器对象
  4. DefaultSecurityManager securityManager = new DefaultSecurityManager();
  5. // 2.设置自定义realm
  6. CustomerMd5Realm realm = new CustomerMd5Realm();
  7. HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
  8. // 使用MD5加密
  9. hashedCredentialsMatcher.setHashAlgorithmName("md5");
  10. // 散列次数
  11. hashedCredentialsMatcher.setHashIterations(1024);
  12. realm.setCredentialsMatcher(hashedCredentialsMatcher);
  13. securityManager.setRealm(realm);
  14. // 3.给 SecurityUtils 全局安全工具类设置安全管理器
  15. SecurityUtils.setSecurityManager(securityManager);
  16. // 4.获取认证主体
  17. Subject subject = SecurityUtils.getSubject();
  18. // 5.创建令牌
  19. UsernamePasswordToken token = new UsernamePasswordToken("xiaochen", "123");
  20. // 6.认证
  21. try {
  22. System.out.println("认证状态:" + subject.isAuthenticated());
  23. subject.login(token);
  24. System.out.println("认证状态:" + subject.isAuthenticated());
  25. } catch (Exception e) {
  26. e.printStackTrace();
  27. }
  28. }
  29. }

4. shiro 中的授权

4.1 授权

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

4.2 关键对象

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

  • Who,即主体(Subject),主体需要访问系统中的资源
  • What,即资源(Resource),如系统菜单、页面、按钮、类方法、系统商品信息等。资源包括资源类型和资源实例,比如商品信息为资源类型,类型为 t01 的商品为资源实例,编号为 001 的商品信息也属于资源实例
  • How,权限/许可(Permission),规定了主体对资源的操作许可,权限离开资源没有意义,如用户查询权限、用户添加权限、某个类方法的调用权限、编号为 001 用户的修改权限等,通过权限可知道主体对哪些资源都有哪些操作许可

4.3 授权方式

基于角色的访问控制,以角色为中心进行访问控制

  1. if(subject.hasRole("admin")){
  2. //操作什么资源
  3. }

基于资源的访问控制,以资源为中心进行访问控制

  1. if(subject.isPermission("user:update:01")){ //资源实例
  2. //对01用户进行修改
  3. }
  4. if(subject.isPermission("user:update:*")){ //资源类型
  5. //对01用户进行修改
  6. }

4.4 权限字符串

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

例子:

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

4.5 授权编程实现

在之前 md5 加密的基础上,实现授权操作

自定义 CustomerMd5Realm

  1. public class CustomerMd5Realm extends AuthorizingRealm {
  2. // 授权
  3. @Override
  4. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
  5. // 获取身份信息
  6. String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();
  7. // 根据身份信息(用户名)从数据库获取当前用户的角色以及权限信息
  8. SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
  9. // 将数据库中查询的角色信息赋值给权限对象
  10. simpleAuthorizationInfo.addRole("admin");
  11. simpleAuthorizationInfo.addRole("user");
  12. // 将数据库中查询的权限信息赋值给权限对象
  13. simpleAuthorizationInfo.addStringPermission("user:*:01");
  14. simpleAuthorizationInfo.addStringPermission("product:create:02");
  15. return simpleAuthorizationInfo;
  16. }
  17. ...
  18. }

授权逻辑

  1. public class TestCustomerMd5RealmAuthenticator {
  2. public static void main(String[] args) {
  3. ...
  4. // 7. 认证用户进行授权
  5. if (subject.isAuthenticated()) {
  6. // 7.1 基于角色权限控制
  7. boolean hasRole = subject.hasRole("admin");
  8. System.out.println("角色校验:" + hasRole);
  9. // 7.2 基于多角色权限控制
  10. boolean hasAllRoles = subject.hasAllRoles(Arrays.asList("admin", "user"));
  11. System.out.println("多角色校验:" + hasAllRoles);
  12. // 7.3 是否具有其中一个角色
  13. boolean[] booleans = subject.hasRoles(Arrays.asList("admin", "user", "super"));
  14. for (boolean aBoolean : booleans) {
  15. System.out.println(aBoolean);
  16. }
  17. // 7.4 基于权限字符串的访问控制
  18. boolean permitted = subject.isPermitted("user:*:01");
  19. System.out.println("资源权限校验:" + permitted);
  20. // 7.5 分布具有哪些资源权限
  21. boolean[] permitted1 = subject.isPermitted("user:*:01", "order:*:10");
  22. for (boolean b : permitted1) {
  23. System.out.println(b);
  24. }
  25. // 7.6 同时具有哪些资源权限
  26. boolean permittedAll = subject.isPermittedAll("user:*:01", "product:*");
  27. System.out.println("多资源权限校验:" + permittedAll);
  28. }
  29. }
  30. }

shiro 学习笔记的更多相关文章

  1. Shiro学习笔记(5)——web集成

    Web集成 shiro配置文件shiroini 界面 webxml最关键 Servlet 測试 基于 Basic 的拦截器身份验证 Web集成 大多数情况.web项目都会集成spring.shiro在 ...

  2. shiro学习笔记_0600_自定义realm实现授权

    博客shiro学习笔记_0400_自定义Realm实现身份认证 介绍了认证,这里介绍授权. 1,仅仅通过配置文件来指定权限不够灵活且不方便.在实际的应用中大多数情况下都是将用户信息,角色信息,权限信息 ...

  3. Shiro学习笔记总结,附加" 身份认证 "源码案例(一)

    Shiro学习笔记总结 内容介绍: 一.Shiro介绍 二.subject认证主体 三.身份认证流程 四.Realm & JDBC reaml介绍 五.Shiro.ini配置介绍 六.源码案例 ...

  4. Shiro 学习笔记(一)——shiro简介

    Apache Shiro 是一个安全框架.说白了,就是进行一下 权限校验,判断下这个用户是否登录了,是否有权限去做这件事情. Shiro 可以帮助我们完成:认证.授权.加密.会话管理.与web 集成. ...

  5. shiro学习笔记_0100_shiro简介

    前言:第一次知道shiro是2016年夏天,做项目时候我要写springmvc的拦截器,申哥看到后,说这个不安全,就给我捣鼓了shiro,我就看了下,从此认识了shiro.此笔记是根据网上的视频教程记 ...

  6. Shiro学习笔记四(Shiro集成WEB)

    这两天由于家里出了点事情,没有准时的进行学习.今天补上之前的笔记 -----没有学不会的技术,只有不停找借口的人 学习到的知识点: 1.Shiro 集成WEB 2.基于角色的权限控制 3.基于权限的控 ...

  7. Shiro学习笔记 三(认证授权)

    第一种首先基于角色的权限控制 1.由于不断的创建SecurityFactory工程等步骤重复多次,所以应该将这些步骤封装成一个工具类 还是首先看一下目录结构 主要用到文件 首先贴一下工具类的方法 pa ...

  8. shiro学习笔记_0400_自定义realm实现身份认证

     自定义Realm实现身份认证 先来看下Realm的类继承关系: Realm接口有三个方法,最重要的是第三个方法: a) String getName():返回此realm的名字 b) boolean ...

  9. Shiro 学习笔记(二)——shiro身份验证

    身份验证: 在应用中证明他就是他本人.一般上用身份证.用户/密码 来证明. 在shiro中,用户需要提供principals (身份)和credentials(证明)给shiro,从而应用能验证用户身 ...

随机推荐

  1. hdoj_Problem1.1.8_A+B for Input-Output Practice (VIII)

    A+B for Input-Output Practice (VIII) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/3276 ...

  2. TCP三次握手四次挥手,通俗易懂版

    三次握手四次挥手 三次握手 其实很好理解,三次握手就是保证双手都有发送和接受的能力.那么最少三次才能验证完成 即----> 客户端发送---服务端收到----服务端发送-- 1.客户端发送 -- ...

  3. 2.3 Core Building Blocks 核心构件

    Core Building Blocks 核心构件 DDD mostly focuses on the Domain & Application Layers and ignores the ...

  4. 【UE4 C++ 基础知识】<1> UPROPERTY宏、属性说明符、元数据说明符

    属性声明 属性使用标准的C++变量语法声明,前面用UPROPERTY宏来定义属性元数据和变量说明符. UPROPERTY([specifier, specifier, ...], [meta(key= ...

  5. Linux argc,argv详解

    来源:微信公众号「编程学习基地」 @ 目录 argc,argv是什么 如何解析程序参数 "选项"是什么? "选项字符串"是什么 解析参数 argc,argv是什 ...

  6. 大闸蟹的 O O 战记

    一. 第四单元架构设计分析 第一次作业,UML类图 第一次作业的主要任务是完成对UML类图的解析并实现查询等操作,需要在课程组给定的框架中添加函数.对于UML类图,其存储是按照元素来存储的,其将所有的 ...

  7. CODING 助力江苏高速信息实现组织敏捷与研发敏捷,领跑智慧交通新基建

    疫情之下的高速公路管控重任 江苏高速公路信息工程有限公司(以下简称:江苏高速信息)成立于 2002 年,是江苏交通控股旗下,专业从事高速公路领域机电系统集成.智能交通软硬件研发.大数据分析运营的高新技 ...

  8. 「笔记」$Min\_25$筛

    总之我也不知道这个奇怪的名字是怎么来的. \(Min\_25\)筛用来计算一类积性函数前缀和. 如果一个积性函数\(F(x)\)在质数单点是一个可以快速计算的关于此质数的多项式. 那么可以用\(Min ...

  9. 关于麦克风的参数介绍 - 驻极体麦克风(ECM)和硅麦(MEMS)

    1.麦克风的分类1.1.动圈式麦克风(Dynamic Micphone)原理:基本构造包含线圈.振膜.永久磁铁三部分.当声波进入麦克风,振膜受到声波的压力而产生振动,与振膜在一起的线圈则开始在磁场中移 ...

  10. Machine learning(3-Linear Algebra Review )

    1.Matrices and vectors Matrix :Rectangular array of numbers a notation R3×3 Vector : An n×1 matrix t ...