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