【Shiro】第三章 Shiro入门(四)

简介: 【Shiro】第三章 Shiro入门(四)

5、身份授权

【1】基本流程

1、首先调用Subject.isPermitted/hasRole接口,其会委托给SecurityManager。

2、SecurityManager接着会委托给内部组件Authorizer;

3、Authorizer再将其请求委托给我们的Realm去做;Realm才是真正干活的;

4、Realm将用户请求的参数封装成权限对象。再从我们重写的doGetAuthorizationInfo方法中获取从数据库中查询到的权限集合。

5、Realm将用户传入的权限对象,与从数据库中查出来的权限对象,进行一一对比。如果用户传入的权限对象在从数据库中查出来的权限对象中,则返回true,否则返回false。

进行授权操作的前提:用户必须通过认证。

在真实的项目中,角色与权限都存放在数据库中。为了快速上手,我们先创建一个自定义DefinitionRealm,模拟它已经登录成功。直接返回一个登录验证凭证,告诉Shiro框架,我们从数据库中查询出来的密码是也是就是你输入的密码。所以,不管用户输入什么,本次登录验证都是通过的。

1. /**
2.      * @Description 认证接口
3.      * @param token 传递登录token
4.      * @return
5.      */
6. @Override
7. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
8. //从AuthenticationToken中获得登录名称
9. String loginName = (String) token.getPrincipal();
10. SecurityService securityService = new SecurityServiceImpl();
11.     Map<String, String> map = securityService.findPasswordByLoginName(loginName);
12. if (map.isEmpty()){
13. throw new UnknownAccountException("账户不存在");
14.     }
15. String salt = map.get("salt");
16. String password = map.get("password");
17. //传递账号和密码:参数1:用户认证凭证信息,参数2:明文密码,参数三:字节salt,参数4:当前DefinitionRealm名称
18. return  new SimpleAuthenticationInfo(loginName,password, ByteSource.Util.bytes(salt),getName());
19. }

好了,接下来,我们要重写我们本小节的核心方法了。在DefinitionRealm中找到下列方法:

1. @Override
2. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
3. return null;
4. }

此方法的传入的参数PrincipalCollection principals,是一个包装对象,它表示"用户认证凭证信息"。包装的是谁呢?没错,就是认证doGetAuthenticationInfo()方法的返回值的第一个参数loginName。你可以通过这个包装对象的getPrimaryPrincipal()方法拿到此值,然后再从数据库中拿到对应的角色和资源,构建SimpleAuthorizationInfo。

1. /**
2.      * @Description 授权方法
3.      */
4. @Override
5. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
6. //拿到用户认证凭证信息
7. String loginName = (String) principals.getPrimaryPrincipal();
8. //从数据库中查询对应的角色和资源
9. SecurityService securityService = new SecurityServiceImpl();
10.     List<String> roles = securityService.findRoleByloginName(loginName);
11.     List<String> permissions = securityService.findPermissionByloginName(loginName);
12. //构建资源校验
13. SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
14.     authorizationInfo.addRoles(roles);
15.     authorizationInfo.addStringPermissions(permissions);
16. return authorizationInfo;
17. }

【2】案例演示

【2.1】需求

1. 1、实现doGetAuthorizationInfo方法实现鉴权
2. 2、使用subject类实现权限的校验

【2.2】实现

【2.2.1】创建项目

拷贝shiro-day01-05-ciphertext-realm新建shiro-day01-06-authentication-realm

【2.2.2】编写SecurityService

在SecurityService中添加

1.  /**
2.      * @Description 查找角色按用户登录名
3.      * @param  loginName 登录名称
4.      * @return
5.      */
6. List<String> findRoleByloginName(String loginName);
7. 
8.  /**
9.      * @Description 查找资源按用户登录名
10.      * @param  loginName 登录名称
11.      * @return
12.      */
13. List<String>  findPermissionByloginName(String loginName);

SecurityServiceImpl添加实现

1. @Override
2. public List<String> findRoleByloginName(String loginName) {
3.     List<String> list = new ArrayList<>();
4.     list.add("admin");
5.     list.add("dev");
6. return list;
7. }
8. 
9. @Override
10. public List<String>  findPermissionByloginName(String loginName) {
11.     List<String> list = new ArrayList<>();
12.     list.add("order:add");
13.     list.add("order:list");
14.     list.add("order:del");
15. return list;
16. }

【2.2.3】编写DefinitionRealm

在DefinitionRealm中修改doGetAuthorizationInfo方法如下

1. /**
2.   * @Description 授权方法
3.   */
4. @Override
5. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
6. //拿到用户认证凭证信息
7. String loginName = (String) principals.getPrimaryPrincipal();
8. //从数据库中查询对应的角色和资源
9. SecurityService securityService = new SecurityServiceImpl();
10.     List<String> roles = securityService.findRoleByloginName(loginName);
11.     List<String> permissions = securityService.findPermissionByloginName(loginName);
12. //构建资源校验
13. SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
14.     authorizationInfo.addRoles(roles);
15.     authorizationInfo.addStringPermissions(permissions);
16. return authorizationInfo;
17. }

【2.2.4】编写HelloShiro

1. package com.itheima.shiro;
2. 
3. import org.apache.shiro.SecurityUtils;
4. import org.apache.shiro.authc.UsernamePasswordToken;
5. import org.apache.shiro.config.IniSecurityManagerFactory;
6. import org.apache.shiro.mgt.SecurityManager;
7. import org.apache.shiro.subject.Subject;
8. import org.apache.shiro.util.Factory;
9. import org.junit.Assert;
10. import org.junit.Test;
11. 
12. /**
13.  * @Description:shiro的第一个例子
14.  */
15. public class HelloShiro {
16. 
17. 
18. @Test
19. public void testPermissionRealm() {
20. Subject subject = shiroLogin("jay", "123");
21. //判断用户是否已经登录
22.         System.out.println("是否登录成功:" + subject.isAuthenticated());
23. 
24. //---------检查当前用户的角色信息------------
25.         System.out.println("是否有管理员角色:"+subject.hasRole("admin"));
26. //---------如果当前用户有此角色,无返回值。若没有此权限,则抛 UnauthorizedException------------
27. try {
28.             subject.checkRole("coder");
29.             System.out.println("有coder角色");
30.         }catch (Exception e){
31.             System.out.println("没有coder角色");
32.         }
33. 
34. //---------检查当前用户的权限信息------------
35.         System.out.println("是否有查看订单列表资源:"+subject.isPermitted("order:list"));
36. //---------如果当前用户有此权限,无返回值。若没有此权限,则抛 UnauthorizedException------------
37. try {
38.             subject.checkPermissions("order:add", "order:del");
39.             System.out.println("有添加和删除订单资源");
40.         }catch (Exception e){
41.             System.out.println("没有有添加和删除订单资源");
42.         }
43. 
44.     }
45. 
46. 
47. /**
48.      * @Description 登录方法
49.      */
50. private Subject shiroLogin(String loginName,String password) {
51. //导入权限ini文件构建权限工厂
52.         Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
53. //工厂构建安全管理器
54. SecurityManager securityManager = factory.getInstance();
55. //使用SecurityUtils工具生效安全管理器
56.         SecurityUtils.setSecurityManager(securityManager);
57. //使用SecurityUtils工具获得主体
58. Subject subject = SecurityUtils.getSubject();
59. //构建账号token
60. UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(loginName, password);
61. //登录操作
62.         subject.login(usernamePasswordToken);
63. return subject;
64.     }
65. }

【2.3】授权源码追踪

(1)客户端调用 subject.hasRole("admin"),判断当前用户是否有"admin"角色权限。

(2)Subject门面对象接收到要被验证的角色信息"admin",并将其委托给securityManager中验证。

(3)securityManager将验证请求再次委托给内部的小弟:内部组件Authorizer authorizer

(4)内部小弟authorizer也是个混子,将其委托给了我们自定义的 去做

(5) 先拿到PrincipalCollection principal对象,同时传入校验的角色循环校验,循环中先创建鉴权信息

(6)先看缓存中是否已经有鉴权信息

(7)都是一群懒货!!最后干活的还是我这个猴子!

【3】小结

1、鉴权需要实现doGetAuthorizationInfo方法

2、鉴权使用门面subject中方法进行鉴权

   以check开头的会抛出异常

   以is和has开头会返回布尔值

相关文章
|
Oracle Java 关系型数据库
三分钟拿下dbeaver企业版
数据库管理工具Dbeaver,开源的企业版,功能丰富
2531 0
三分钟拿下dbeaver企业版
|
分布式计算 关系型数据库 数据库连接
MaxCompute数据问题之数据迁移如何解决
MaxCompute数据包含存储在MaxCompute服务中的表、分区以及其他数据结构;本合集将提供MaxCompute数据的管理和优化指南,以及数据操作中的常见问题和解决策略。
233 0
|
Java API Android开发
【错误记录】Android 注解处理器报错 ( 非法的类文件开始 , 请删除该文件或确保该文件位于正确的类路径子目录中。 )
【错误记录】Android 注解处理器报错 ( 非法的类文件开始 , 请删除该文件或确保该文件位于正确的类路径子目录中。 )
827 0
【错误记录】Android 注解处理器报错 ( 非法的类文件开始 , 请删除该文件或确保该文件位于正确的类路径子目录中。 )
|
存储 SQL 数据库
数据库设计案例:电商系统数据库设计实践
数据库设计案例:电商系统数据库设计实践
2308 1
|
11月前
|
安全 Java 测试技术
springboot之SpringBoot单元测试
本文介绍了Spring和Spring Boot项目的单元测试方法,包括使用`@RunWith(SpringJUnit4ClassRunner.class)`、`@WebAppConfiguration`等注解配置测试环境,利用`MockMvc`进行HTTP请求模拟测试,以及如何结合Spring Security进行安全相关的单元测试。Spring Boot中则推荐使用`@SpringBootTest`注解简化测试配置。
388 4
|
存储 弹性计算 缓存
阿里云服务器通用型g8i实例最新收费标准与性能介绍
阿里云ECS通用型g8i服务器采用阿里云全新CIPU架构,可提供稳定的算力输出、更强劲的I/O引擎以及芯片级的安全加固。ECS通用型g8i实例支持开启或关闭超线程配置,单台g8i实例最高支持100万IOPS。阿里云ECS通用型g8i实例CPU采用Intel®Xeon®Emerald Rapids或者Intel®Xeon®Sapphire Rapids,主频不低于2.7 GHz,全核睿频3.2GHz。本文为大家介绍通用型g8i实例最新收费标准及性能。
阿里云服务器通用型g8i实例最新收费标准与性能介绍
|
NoSQL Java Redis
Spring Boot集成Redisson详细介绍
Redisson是一个用于Java的分布式和高可用的Java对象的框架,它基于Redis实现。在Spring Boot应用程序中集成Redisson可以帮助我们更轻松地实现分布式锁、分布式对象、分布式集合等功能。本文将介绍如何在Spring Boot项目中集成Redisson,并展示一些基本用法。
1922 2
Spring Boot集成Redisson详细介绍
|
JSON 前端开发 API
使用微信JS-SDK调用发票接口的完整开发指南
本文介绍了如何使用微信JS-SDK的`chooseInvoiceTitle`接口来调用微信的发票功能。通过微信发票接口,用户可以选择开具个人或单位发票,并获取相关发票信息,如抬头、税号、公司地址等。在文中,详细描述了JS-SDK的初始化、发票接口的调用方式,并提供了完整的代码示例。文章还介绍了如何处理返回的发票信息,帮助开发者快速集成微信发票功能。
461 2
|
缓存 Cloud Native 测试技术
Golang 乐观锁实战:Gorm 乐观锁的优雅使用
在现代软件开发中,数据一致性是一个永恒的话题。随着系统规模的扩大和并发操作的增加,如何有效地处理并发冲突,确保数据的完整性,成为了开发者必须面对的挑战。本文将带你深入了解 Golang 中 Gorm ORM 库的乐观锁机制,并通过实际示例,展示如何在项目中优雅地使用乐观锁。
|
供应链 搜索推荐 数据挖掘
探索增强现实(AR)在零售业的应用
【5月更文挑战第12天】本文探讨了AR技术如何革新零售业,包括虚拟试衣间提升购物效率、产品信息展示增强认知、导航导购优化购物体验及互动营销增加用户粘性。AR技术能提升消费者体验,提高零售业效率,并增强品牌竞争力。随着AR的发展,零售业将迎来更多创新应用。
下一篇
开通oss服务