shiro 再次通过源码谈谈登录的流程,之前理解的不是很清楚!
来源:互联网 发布:fanuc编程模拟软件 编辑:程序博客网 时间:2024/06/03 10:01
PrincipalCollection这个可以理解为当事人的信息!昨天在授权信息检查的时候,一直在传递这个信息,当时不是很理解,所以今天继续说说这个设计的意思到底是什么回事。以及登录流程之前疏忽的一些重要的信息,都统统的补齐。
subject.login(token);这个是今天的主要的角色,刚刚断点跟踪了一会才理解了到时是在做什么。
protected void login(String configFile, String username, String password) { //1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager Factory<org.apache.shiro.mgt.SecurityManager> factory = new IniSecurityManagerFactory(configFile); //2、得到SecurityManager实例 并绑定给SecurityUtils org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager); //3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证) Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, password); subject.login(token); }
(1)
DelegatingSubject这个是Subject的实现类,主要的成员函数如下,一个是当前的管家的引用,一个是PrincipalCollection 当事人的信息,具体代表什么意思细细的道来。
protected PrincipalCollection principals; protected boolean authenticated; protected String host; protected Session session; protected boolean sessionCreationEnabled; protected transient SecurityManager securityManager;
进入到了Subject的实现类的login方法中,因为我们知道这些验证的信息都是来至于我们的管家的验证。
DelegatingSubject->public void login(AuthenticationToken token)
(2)从这里开始,又开始交给管家去处理了,所以管家的继承图不能少啊!
DefaultSecurityManager.login
public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException { AuthenticationInfo info; try { //这里就是给继承图的上面的处理认证信息 info = authenticate(token); } catch (AuthenticationException ae) { try { onFailedLogin(token, ae, subject); } catch (Exception e) { if (log.isInfoEnabled()) { } } throw ae; } //根据当前的信息,创造一个Subject信息。 Subject loggedIn = createSubject(token, info, subject); onSuccessfulLogin(token, info, loggedIn); return loggedIn; }
AuthenticatingSecurityManager
//成员变量里面的认证的门面哦~
private Authenticator authenticator;
//构造函数里面创建
this.authenticator = new ModularRealmAuthenticator();
AuthenticationInfo 作为返回信息,这里面试啥呢?还是不给力投路,一会看图片就知道了。认证之后,返回呢一个认证信息
public AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException { return this.authenticator.authenticate(token); }
ModularRealmAuthenticator的上面呢,还继承了一个主要处理验证成功和失败的监听通知的传送!
ModularRealmAuthenticator->单个的验证realm在我们处理的时候其实这些信息已经全部的在了。通过配置读取的时候全部都设置好了。reaml处理数据的信息哦,无论是验证还是权限的信息都需要这个的处理哦!这里只配置了原始的默认的,只有一个Realm protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException { assertRealmsConfigured(); Collection<Realm> realms = getRealms(); if (realms.size() == 1) { return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken); } else { return doMultiRealmAuthentication(realms, authenticationToken); } }
这里继续,发现是realm.getAuthenticationInfo(token); 这里返回的才是当前处理的重点,就是当前客户的信息。我们自己定义的时候都必须返回这AuthenticationInfo 的实现类才可以哦。
protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) { if (!realm.supports(token)) { throw new UnsupportedTokenException(msg); } AuthenticationInfo info = realm.getAuthenticationInfo(token); if (info == null) { throw new UnknownAccountException(msg); } return info; }
realm又一次进入到了realm的处理的世界,我们知道real的世界中呢,又是一个非常擅长使用template方法,继承结构的。所以还是再次来看看继承图,看这里有认证realm有授权的realm分工的很清楚啊,还有管理缓存的realm哦。这样的设计你说好不好呢?
AuthenticatingRealm认证的realm哦,进入到了这里,注意到这个是final方法,必须在这里验证哦~看看有没有缓存,没有缓存直接在进行下一步,查询信息
public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { AuthenticationInfo info = getCachedAuthenticationInfo(token); if (info == null) { //otherwise not cached, perform the lookup: info = doGetAuthenticationInfo(token); log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info); if (token != null && info != null) { cacheAuthenticationInfoIfPossible(token, info); } } else { log.debug("Using cached authentication info [{}] to perform credentials matching.", info); } if (info != null) { assertCredentialsMatch(token, info); } else { log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}]. Returning null.", token); } return info; }
我们使用的是默认的IniRealm进行处理哦~,这个不能理解错误了。进入到了SimpleAccountRealm这个是IniRealm的父类的信息哦,这里的信息都是保存在内存中的,有一个users和roles的读写锁哦。具体的users是什么和roles这个Map里面的信息是什么一个是username->SimpleAccount 一个是roleName->SimpleRole
public class SimpleAccountRealm extends AuthorizingRealm { //TODO - complete JavaDoc protected final Map<String, SimpleAccount> users; //username-to-SimpleAccount protected final Map<String, SimpleRole> roles; //roleName-to-SimpleRole protected final ReadWriteLock USERS_LOCK; protected final ReadWriteLock ROLES_LOCK; public SimpleAccountRealm() { this.users = new LinkedHashMap<String, SimpleAccount>(); this.roles = new LinkedHashMap<String, SimpleRole>(); USERS_LOCK = new ReentrantReadWriteLock(); ROLES_LOCK = new ReentrantReadWriteLock(); //SimpleAccountRealms are memory-only realms - no need for an additional cache mechanism since we're //already as memory-efficient as we can be: setCachingEnabled(false); } public SimpleAccountRealm(String name) { this(); setName(name); } protected SimpleAccount getUser(String username) { USERS_LOCK.readLock().lock(); try { return this.users.get(username); } finally { USERS_LOCK.readLock().unlock(); } } public void addAccount(String username, String password) { addAccount(username, password, (String[]) null); } public void addAccount(String username, String password, String... roles) { Set<String> roleNames = CollectionUtils.asSet(roles); SimpleAccount account = new SimpleAccount(username, password, getName(), roleNames, null); add(account); } protected String getUsername(SimpleAccount account) { return getUsername(account.getPrincipals()); } protected String getUsername(PrincipalCollection principals) { return getAvailablePrincipal(principals).toString(); } protected void add(SimpleAccount account) { String username = getUsername(account); USERS_LOCK.writeLock().lock(); try { this.users.put(username, account); } finally { USERS_LOCK.writeLock().unlock(); } } protected SimpleRole getRole(String rolename) { ROLES_LOCK.readLock().lock(); try { return roles.get(rolename); } finally { ROLES_LOCK.readLock().unlock(); } } public boolean roleExists(String name) { return getRole(name) != null; } public void addRole(String name) { add(new SimpleRole(name)); } protected void add(SimpleRole role) { ROLES_LOCK.writeLock().lock(); try { roles.put(role.getName(), role); } finally { ROLES_LOCK.writeLock().unlock(); } } protected static Set<String> toSet(String delimited, String delimiter) { if (delimited == null || delimited.trim().equals("")) { return null; } Set<String> values = new HashSet<String>(); String[] rolenamesArray = delimited.split(delimiter); for (String s : rolenamesArray) { String trimmed = s.trim(); if (trimmed.length() > 0) { values.add(trimmed); } } return values; } protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken upToken = (UsernamePasswordToken) token; SimpleAccount account = getUser(upToken.getUsername()); if (account != null) { if (account.isLocked()) { throw new LockedAccountException("Account [" + account + "] is locked."); } if (account.isCredentialsExpired()) { String msg = "The credentials for account [" + account + "] are expired"; throw new ExpiredCredentialsException(msg); } } return account; } protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = getUsername(principals); USERS_LOCK.readLock().lock(); try { return this.users.get(username); } finally { USERS_LOCK.readLock().unlock(); } }}
这里先别管之前的验证了,先看看当前的user和roles到底是什么东西
这里的信息都是之前重Ini文件中获取过来,然后转换的哦!这个过程还是需要了解清楚的。
在来详细的看看user
在来详细看看roles对于昨天的学习,这个分段的处理信息Permission这个很好理解了哦~,当前角色对于的权限嘛是不是,这里看起来比user里面的要简单了很多啊,所以想看看roles怎么定义的!
SimpleRole 一个角色对应的所有的权限~Permission 这个Permission可以自己去处理,也不一定是系统默认定义的哦,原来那种是分段处理的哈哈,就像看到的这种样子。
/** * A simple representation of a security role that * has a name and a collection of permissions. This object can be * used internally by Realms to maintain authorization state. *这个是被realms内部使用的,维护状态 * @since 0.2 */public class SimpleRole implements Serializable { protected String name = null; protected Set<Permission> permissions; public SimpleRole() { } public SimpleRole(String name) { setName(name); } public SimpleRole(String name, Set<Permission> permissions) { setName(name); setPermissions(permissions); } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Permission> getPermissions() { return permissions; } public void setPermissions(Set<Permission> permissions) { this.permissions = permissions; } public void add(Permission permission) { Set<Permission> permissions = getPermissions(); if (permissions == null) { permissions = new LinkedHashSet<Permission>(); setPermissions(permissions); } permissions.add(permission); } public void addAll(Collection<Permission> perms) { if (perms != null && !perms.isEmpty()) { Set<Permission> permissions = getPermissions(); if (permissions == null) { permissions = new LinkedHashSet<Permission>(perms.size()); setPermissions(permissions); } permissions.addAll(perms); } } public boolean isPermitted(Permission p) { Collection<Permission> perms = getPermissions(); if (perms != null && !perms.isEmpty()) { for (Permission perm : perms) { if (perm.implies(p)) { return true; } } } return false; } public int hashCode() { return (getName() != null ? getName().hashCode() : 0); } public boolean equals(Object o) { if (o == this) { return true; } if (o instanceof SimpleRole) { SimpleRole sr = (SimpleRole) o; //only check name, since role names should be unique across an entire application: return (getName() != null ? getName().equals(sr.getName()) : sr.getName() == null); } return false; } public String toString() { return getName(); }}
SimpleAccount这个包含了很多的当前账号的信息,包含了用户名,凭证(密码)权限信息,我们看哈英文怎么说的。
contains principal (可以理解为账号)and credential (可以理解为密码)and authorization information(授权的信息) (roles and permissions) as instance variables。这个就是对于账号的信息哦
这个SimpleAccount还是比较大复杂的,保存了账号的凭证,密码,还有权限信息,其实这些在接口中都有体现,我们先看看继承的接口的信息把。
AuthenticationInfo 认证信息
public interface AuthenticationInfo extends Serializable { /** * 返回所有的principals和当前的Subject相关的,Each principal is an identifying piece of(唯一的标识) * information useful to the application such as a username, or user id, a given name, etc - anything useful * to the application to identify the current Subject.可以识别当前的Subject的 * The returned PrincipalCollection should not contain any credentials used to verify principals, such * as passwords, private keys, etc. Those should be instead returned by {@link #getCredentials() getCredentials()}. *不应该包含秘密的信息,也就是说Authentication(认证信息)在Subject为啥只有PrincipalCollection 而没得密码 */ PrincipalCollection getPrincipals(); /** * Returns the credentials associated with the corresponding Subject. A credential verifies one or more of the * {@link #getPrincipals() principals} associated with the Subject, such as a password or private key. Credentials * are used by Shiro particularly during the authentication process to ensure that submitted credentials * during a login attempt match exactly the credentials here in the <code>AuthenticationInfo</code> instance. *这个就是密码啦! */ Object getCredentials();}
SaltedAuthenticationInfo 这个是加盐操作的接口,一般不直接通过密码就行比较,增加处理,盐通常由安全的伪随机数生成器生成,因此它们是有效的,盐值应安全存储在账户信息侧,以确保它与帐户的凭据一起维护。
public interface SaltedAuthenticationInfo extends AuthenticationInfo { /** * Returns the salt used to salt the account's credentials or {@code null} if no salt was used. * * @return the salt used to salt the account's credentials or {@code null} if no salt was used. */ ByteSource getCredentialsSalt();}
MergableAuthenticationInfo合并认证信息~一般不会用到吧!
public interface MergableAuthenticationInfo extends AuthenticationInfo { /** * Merges the given {@link AuthenticationInfo} into this instance. The specific way * that the merge occurs is up to the implementation, but typically it involves combining * the principals and credentials together in this instance. The <code>info</code> argument should * not be modified in any way. * * @param info the info that should be merged into this instance. */ void merge(AuthenticationInfo info);}
Account账号的信息包含认证的信息和授权的信息
public interface Account extends AuthenticationInfo, AuthorizationInfo {一个是认证的信息,一个是授权的信息~哈哈写不写都可以}
AuthorizationInfo 授权信息的集合
//授权信息public interface AuthorizationInfo extends Serializable { /** * Returns the names of all roles assigned to a corresponding Subject. */ Collection<String> getRoles(); Collection<String> getStringPermissions(); /** * Returns all type-safe {@link Permission Permission}s assigned to the corresponding Subject. The permissions * returned from this method plus any returned from {@link #getStringPermissions() getStringPermissions()} * represent the total set of permissions. The aggregate set is used to perform a permission authorization check. * 返回所有的权限的信息当前的用户拥有的 * @return all type-safe {@link Permission Permission}s assigned to the corresponding Subject. */ Collection<Permission> getObjectPermissions();}
SimpleAccount好复杂啊!
下面的两个成员变量主要的实现了认证和授权这两个接口哦~,代理过去处理
/** * The authentication information (principals and credentials) for this account. */ private SimpleAuthenticationInfo authcInfo; /** * The authorization information for this account. */ private SimpleAuthorizationInfo authzInfo;
SimpleAuthorizationInfo 这个比较简单,包含了角色信息和权限咯~~
public class SimpleAuthorizationInfo implements AuthorizationInfo { /** * The internal roles collection. */ protected Set<String> roles; /** * Collection of all string-based permissions associated with the account. */ protected Set<String> stringPermissions; /** * Collection of all object-based permissions associaed with the account. */ protected Set<Permission> objectPermissions;}
SimpleAuthenticationInfo 权限验证这个比较复杂啊~但是和还是一样的身份的,盐,密码。 PrincipalCollection 这个身份是一个重点,因为每一个Subject的成员变量中也拥有一个这样的变量。这里面包含了验证的realm,对应的用户的信息!
public class SimpleAuthenticationInfo implements MergableAuthenticationInfo, SaltedAuthenticationInfo { /** * The principals identifying the account associated with this AuthenticationInfo instance. */ protected PrincipalCollection principals; /** * The credentials verifying the account principals. */ protected Object credentials; /** * Any salt used in hashing the credentials. * * @since 1.1 */ protected ByteSource credentialsSalt; /** * Default no-argument constructor. */ public SimpleAuthenticationInfo() { } /** * Constructor that takes in a single 'primary' principal of the account and its corresponding credentials, * associated with the specified realm. * <p/> * This is a convenience constructor and will construct a {@link PrincipalCollection PrincipalCollection} based * on the {@code principal} and {@code realmName} argument. * * @param principal the 'primary' principal associated with the specified realm. * @param credentials the credentials that verify the given principal. * @param realmName the realm from where the principal and credentials were acquired. */ public SimpleAuthenticationInfo(Object principal, Object credentials, String realmName) { this.principals = new SimplePrincipalCollection(principal, realmName); this.credentials = credentials; } /** * Constructor that takes in a single 'primary' principal of the account, its corresponding hashed credentials, * the salt used to hash the credentials, and the name of the realm to associate with the principals. * <p/> * This is a convenience constructor and will construct a {@link PrincipalCollection PrincipalCollection} based * on the <code>principal</code> and <code>realmName</code> argument. * * @param principal the 'primary' principal associated with the specified realm. * @param hashedCredentials the hashed credentials that verify the given principal. * @param credentialsSalt the salt used when hashing the given hashedCredentials * @param realmName the realm from where the principal and credentials were acquired. * @see org.apache.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher * @since 1.1 */ public SimpleAuthenticationInfo(Object principal, Object hashedCredentials, ByteSource credentialsSalt, String realmName) { this.principals = new SimplePrincipalCollection(principal, realmName); this.credentials = hashedCredentials; this.credentialsSalt = credentialsSalt; } /** * Constructor that takes in an account's identifying principal(s) and its corresponding credentials that verify * the principals. * * @param principals a Realm's account's identifying principal(s) * @param credentials the accounts corresponding principals that verify the principals. */ public SimpleAuthenticationInfo(PrincipalCollection principals, Object credentials) { this.principals = new SimplePrincipalCollection(principals); this.credentials = credentials; } /** * Constructor that takes in an account's identifying principal(s), hashed credentials used to verify the * principals, and the salt used when hashing the credentials. * * @param principals a Realm's account's identifying principal(s) * @param hashedCredentials the hashed credentials that verify the principals. * @param credentialsSalt the salt used when hashing the hashedCredentials. * @see org.apache.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher * @since 1.1 */ public SimpleAuthenticationInfo(PrincipalCollection principals, Object hashedCredentials, ByteSource credentialsSalt) { this.principals = new SimplePrincipalCollection(principals); this.credentials = hashedCredentials; this.credentialsSalt = credentialsSalt; } public String toString() { return principals.toString(); }}
SimplePrincipalCollection继承了 PrincipalCollection
因为可能一个用户有很多的唯一标识符比如电话,邮箱等等~处理这个信息的时候做了个心眼SimplePrincipalCollection
SimplePrincipalCollection
private Map<String, Set> realmPrincipals; 一个是realm的名字,一个是对应当前的用户标识的集合。
SimpleAccountRealm主要的都知道了,那么我们返回来啦,继续讲解验证。
这里通过用户的名字获取到SimpleAccountRealm中 protected final Map< String, SimpleAccount> users; 保存的用户的信息,得到SimpleAccount的信息。
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken upToken = (UsernamePasswordToken) token; SimpleAccount account = getUser(upToken.getUsername()); if (account != null) { if (account.isLocked()) { throw new LockedAccountException("Account [" + account + "] is locked."); } if (account.isCredentialsExpired()) { String msg = "The credentials for account [" + account + "] are expired"; throw new ExpiredCredentialsException(msg); } } return account; }
得到了这个信息之后,在返回验证realm中去检查当前的的AuthenticationToken 中的密码 和这个获取出来信息的密码一样不~一样就成功了。
AuthenticatingRealm
public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { AuthenticationInfo info = getCachedAuthenticationInfo(token); if (info == null) { //otherwise not cached, perform the lookup: info = doGetAuthenticationInfo(token); log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info); if (token != null && info != null) { cacheAuthenticationInfoIfPossible(token, info); } } else { log.debug("Using cached authentication info [{}] to perform credentials matching.", info); } if (info != null) { //这里就是去检验啦~~看看密码信息一样不! assertCredentialsMatch(token, info); } else { log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}]. Returning null.", token); } return info; }
具体的密码的比较~的设计明天再说~~
- shiro 再次通过源码谈谈登录的流程,之前理解的不是很清楚!
- Shiro源码分析----登录流程
- 不是很清楚里面的事
- glOrtho,glFrustum,gluPerspective的理解,很清楚
- shiro的认证思路分析(即登录,流程)
- shiro认证的流程
- jeesite的shiro流程
- 键盘 不是很清楚
- 还不是很清楚
- 漫谈linux文件IO--io流程讲的很清楚
- 再次谈谈easyui datagrid 的数据加载
- 再次谈谈easyui datagrid 的数据加载
- 再次谈谈easyui datagrid 的数据加载
- 再次谈谈easyui datagrid 的数据加载
- 谈谈HTTP的流程
- shiro登录流程
- shiro登录验证(登录跳转到指定页面,验证码验证,不注销之前已登录用户下,再次登录)
- 退出登录清楚以前的activity
- 还是没有题目
- 通用代码管理
- Linux Tab键无法补全
- 算法 批处理作业调度
- CentOS下如何完全卸载MySQL
- shiro 再次通过源码谈谈登录的流程,之前理解的不是很清楚!
- 12.玩转Spring Boot 事务管理
- erdaicms首款基于weui(微信网页开发样式库)的前端模版上线
- CVPR 2016-12-20
- 卷积神经网络反向传播推导
- VxWorks -- 信号量
- Python爬虫包 BeautifulSoup 学习(三) 实例
- sicily Message Flood STL中set和map的应用
- 二分搜索