shiro基础之认证授权

mac2022-06-30  22

复习学习建议: 1.了解整体架构以及一些基本概念词汇(https://www.cnblogs.com/e206842/p/9047263.html 该博文的第一部分) 2.学习本篇博文,学习shiro基本流程和原理 3.学习shiro与spring的整合(https://www.cnblogs.com/e206842/p/9047263.html 该博文的第二部分)

一、从Helloworld探究原理

public static void main(String[] args) { Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager); // 获取当前的 Subject. 调用 SecurityUtils.getSubject(); Subject currentUser = SecurityUtils.getSubject(); // Do some stuff with a Session (no need for a web or EJB container!!!) // 测试使用 Session // 获取 Session: Subject#getSession() Session session = currentUser.getSession(); session.setAttribute("someKey", "aValue"); String value = (String) session.getAttribute("someKey"); if (value.equals("aValue")) { log.info("---> Retrieved the correct value! [" + value + "]"); } // let's login the current user so we can check against roles and permissions: // 测试当前的用户是否已经被认证. 即是否已经登录. // 调动 Subject 的 isAuthenticated() if (!currentUser.isAuthenticated()) { // 把用户名和密码封装为 UsernamePasswordToken 对象 UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa"); // rememberme token.setRememberMe(true); try { // 执行登录. currentUser.login(token); } // 若没有指定的账户, 则 shiro 将会抛出 UnknownAccountException 异常. catch (UnknownAccountException uae) { log.info("----> There is no user with username of " + token.getPrincipal()); return; } // 若账户存在, 但密码不匹配, 则 shiro 会抛出 IncorrectCredentialsException 异常。 catch (IncorrectCredentialsException ice) { log.info("----> Password for account " + token.getPrincipal() + " was incorrect!"); return; } // 用户被锁定的异常 LockedAccountException catch (LockedAccountException lae) { log.info("The account for username " + token.getPrincipal() + " is locked. " + "Please contact your administrator to unlock it."); } // ... catch more exceptions here (maybe custom ones specific to your application? // 所有认证时异常的父类. catch (AuthenticationException ae) { //unexpected condition? error? } } //认证之后授权 //test a role: // 测试是否有某一个角色. 调用 Subject 的 hasRole 方法. if (currentUser.hasRole("schwartz")) { log.info("----> May the Schwartz be with you!"); } else { log.info("----> Hello, mere mortal."); return; } //a (very powerful) Instance Level permission: // 测试用户是否具备某一个行为. if (currentUser.isPermitted("user:delete:zhangsan")) { log.info("----> You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'. " + "Here are the keys - have fun!"); } else { log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!"); } }

二、执行流程

1、通过ini配置文件创建securityManagerhelloWord使用的读取ini(含有用户、角色和权限配置)文件的形式,使用的是IniRealm ,正式使用时ini文件中的信息来自于通过自定义realm(继承AuthorizingRealm即可)查询的数据库

2、调用subject.login方法主体提交认证,提交的token 3、securityManager进行认证,securityManager最终由ModularRealmAuthenticator进行认证。

Authenticator 可能会委托给相应的 AuthenticationStrategy 进 行多 Realm 身份验证,默认 ModularRealmAuthenticator 会调用 AuthenticationStrategy 进行多 Realm 身份验证

4、ModularRealmAuthenticator调用IniRealm(给realm传入token) 去ini配置文件中查询用户信息 5、IniRealm根据输入的token(UsernamePasswordToken)从 shiro-first.ini查询用户信息,根据账号查询用户信息(账号和密码) 如果查询到用户信息,就给ModularRealmAuthenticator返回用户信息(账号和密码)AuthenticationInfo正式使用时:在自定义的realm重写父类的doGetAuthenticationInfo的方法中,构建用户信息

//自定义relam public class ShiroRealm extends AuthorizingRealm { @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { System.out.println("[FirstRealm] doGetAuthenticationInfo"); //1. 把 AuthenticationToken 转换为 UsernamePasswordToken UsernamePasswordToken upToken = (UsernamePasswordToken) token; //2. 从 UsernamePasswordToken 中来获取 username String username = upToken.getUsername(); //3. 调用数据库的方法, 从数据库中查询 username 对应的用户记录 System.out.println("从数据库中获取 username: " + username + " 所对应的用户信息."); //4. 若用户不存在, 则可以抛出 UnknownAccountException 异常 if("unknown".equals(username)){ throw new UnknownAccountException("用户不存在!"); } //5. 根据用户信息的情况, 决定是否需要抛出其他的 AuthenticationException 异常. if("monster".equals(username)){ throw new LockedAccountException("用户被锁定"); } //6. 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo //以下信息是从数据库中获取的. //1). principal: 认证的实体信息. 可以是 username, 也可以是数据表对应的用户的实体类对象. Object principal = username; //2). credentials: 密码. Object credentials = null; //"fc1709d0a95a6be30bc5926fdb7f22f4"; if("admin".equals(username)){ credentials = "038bdaf98f2037b31f1e75b5b4c9b26e"; }else if("user".equals(username)){ credentials = "098d2c478e9c11555ce2823231e02ec1"; } //3). realmName: 当前 realm 对象的 name. 调用父类的 getName() 方法即可 String realmName = getName(); //4). 盐值. ByteSource credentialsSalt = ByteSource.Util.bytes(username); SimpleAuthenticationInfo info = null; //new SimpleAuthenticationInfo(principal, credentials, realmName); info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName); return info; } }

如果查询不到,就给ModularRealmAuthenticator返回null 6、ModularRealmAuthenticator接收IniRealm返回Authentication认证信息 如果返回的认证信息是null,ModularRealmAuthenticator抛出异常 (org.apache.shiro.authc.UnknownAccountException) 如果返回的认证信息不是null(说明inirealm找到了用户),对IniRealm返回用户密码 (在ini文件中存在)和 token中的密码 进行对比,如果不一致抛出异常(org.apache.shiro.authc.IncorrectCredentialsException)

7、内部密码比对示意图

AuthenticationStrategy • AuthenticationStrategy 接口的默认实现: • FirstSuccessfulStrategy:只要有一个 Realm 验证成功即可,只返回第 一个 Realm 身份验证成功的认证信息,其他的忽略; • AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,和 FirstSuccessfulStrategy 不同,将返回所有Realm身份验证成功的认证信 息; • AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有 Realm身份验证成功的认证信息,如果有一个失败就失败了。 • ModularRealmAuthenticator 默认是 AtLeastOneSuccessfulStrategy 策略

三、授权执行流程

1、首先调用 Subject.isPermitted/hasRole 接口,其会委托给SecurityManager,而 SecurityManager 接着会委托给 Authorizer; 2、Authorizer是真正的授权者,如果调用如isPermitted(“user:view”),其首先会通过PermissionResolver 把字符串转换成相应的 Permission 实例; 3、在进行授权之前,其会调用相应的 Realm 获取 Subject 相应的角色/权限信息AuthorizationInfo用于匹配传入的角色/权限; 4、Authorizer 会判断 Realm 的角色/权限是否和传入的匹配,如果有多个Realm,会委托给 ModularRealmAuthorizer 进行循环判断,如果匹配如 isPermitted/hasRole 会返回true,否则返回false表示授权失败。 5、授权内部示意图

转载于:https://www.cnblogs.com/laoyin666/p/10625135.html

最新回复(0)