【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开头会返回布尔值

相关文章
|
7月前
|
Java Maven
Shiro学习-快速入门(二)
Shiro学习-快速入门(二)
35 0
|
9月前
|
安全 数据安全/隐私保护
【Shiro】第三章 Shiro入门(一)
【Shiro】第三章 Shiro入门
53 1
|
9月前
|
存储 算法 数据安全/隐私保护
【Shiro】第三章 Shiro入门(三)
【Shiro】第三章 Shiro入门(三)
60 1
|
9月前
|
存储 算法 程序员
【Shiro】第三章 Shiro入门(二)
【Shiro】第三章 Shiro入门(二)
56 1
|
9月前
|
存储 缓存 安全
【Shiro】第二章 Shiro概述
【Shiro】第二章 Shiro概述
62 0
|
9月前
|
存储 缓存 安全
Shiro学习之Shiro简介
Shiro学习之Shiro简介
71 0
|
9月前
|
Java API 数据库
Shiro学习之Shiro基本使用(1)
Shiro学习之Shiro基本使用(1)
63 0
|
9月前
|
Java 数据库 数据安全/隐私保护
Shiro学习之Shiro基本使用(2)
Shiro学习之Shiro基本使用(2)
39 0
|
存储 数据采集 缓存
Shiro简介
.什么是Shiro - .ApacheShiro 是一个Java的安全(权限)框架。 - .Shiro可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JavaEE环境。 - .Shiro可以完成,认证,授权,加密,会话管理,Web集成,缓存等。
Shiro简介
|
Java 网络安全 数据库
shiro实战教程(二)
shiro实战教程(二)
195 1
shiro实战教程(二)