shiro:
流程:
初始化SecurityManager工厂 => 获取SecurityManager => 获取subject => 根据用户名密码创建token => subject.login(token)验证 => 调用自定义的realms:
实现AuthorizingRealm自定义的realms验证流程:
实现doGetAuthenticationInfo(token)方法获取AuthenticationInfo对象 => 通过CredentialsMatcher对象doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info)方法验证AuthenticationInfo
subject.login(token)调用时发生了什么?
从源码可以得知Subject是接口,实现该接口的类有:
Subject(接口):
DelegatingSubject(实现类):从源码可以得知是subject默认实现,因为有login(token)方法
WebDelegatingSubject(实现类):
DelegatingSubject.login():方法会调用securityManager.login(this, token)方法;
调用此方法中最重要的一个过程是调用new ModularRealmAuthenticator()对象的doAuthenticate(AuthenticationToken authenticationToken)方法
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);
}
}
从以上方法可以看出 getRealms()获取我们自定义配置的realms,然后依次调用
1.========主要接口=========
securityManager:
主要方法:
Subject login(Subject subject, AuthenticationToken authenticationToken) throws AuthenticationException;
void logout(Subject subject);
Subject createSubject(SubjectContext context);
Realm:
主要方法:
String getName();
boolean supports(AuthenticationToken token);
AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException;
CredentialsMatcher:
主要方法:
boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info);
2.=====主要接口的实现关系=======
实现securityManager接口实现关系:
securityManager:
CachingSecurityManager(抽象实现类):
RealmSecurityManager(抽象实现类):
AuthenticatingSecurityManager:(抽象实现类)
AuthorizingSecurityManager(抽象实现类):
SessionsSecurityManager(抽象实现类):
DefaultSecurityManager(实现类):
实现Realm接口实现关系:
Realm(接口)
CachingReaml(抽象类):只是添加了cacheManager属性并没有实现Realm接口方法
AuthenticatingRealm(抽象类):实现了Realm接口getAuthenticationInfo(AuthenticationToken token)方法并定义为final类型,也就是说从该层开始以下的类不能在重写该方法只能重写新引入doGetAuthenticationInfo(token)抽象方法获取AuthenticationInfo对象;引入CredentialsMatcher接口对象,通过调用该对象的doCredentialsMatch(token, info)方法实现验证;(回调函数) 注意:/**getAuthenticationInfo方法定义为final,不能被重写**/ 啰嗦这么多总结一句话:就是AuthenticatingRealm类已经对getAuthenticationInfo(AuthenticationToken token)方法定制好了业务逻辑,只需要实现里面的细节
AuthorizingRealm(抽象类):doGetAuthenticationInfo(token)实现该方法,实现自己的业务逻辑
实现CredentialsMatcher接口实现关系:
CredentialsMatcher:
AllowAllCredentialsMatcher(实现类):doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) return true; 所有都通过验证
PasswordMatcher(实现类):该类有passwordService对象,通过passwordService.passwordsMatch(submittedPassword, formatted)实现加密密码的验证;
SimpleCredentialsMatcher(实现类):简单的身份验证
3.=======关联的一些重要接口==========
PasswordService(接口):
主要方法:
//顾名思义对密码加密
String encryptPassword(Object plaintextPassword) throws IllegalArgumentException;
//加密密码的验证
boolean passwordsMatch(Object submittedPlaintext, String encrypted);
实现关系:
HashingPasswordService(接口):实现PasswordService
DefaultPasswordService(实现类):默认:DEFAULT_HASH_ALGORITHM = "SHA-256"
总结:
实现自定义realm:
1)实现Realm接口,实现简单的自定义realm
2)继承AuthorizingRealm(抽象类),实现doGetAuthenticationInfo(token)方法,可以给自定义的realm设置CredentialsMatcher接口对象,如果不设置默认为SimpleCredentialsMatcher;
如果想对密码加密需要设置PasswordMatcher接口,该对象默认使用DefaultPasswordService(PasswordService接口对象);
也可以自定义PasswordService接口对象并传入,这样就可以按照自己的需求去加密密码,以及验证密码;
继承AuthorizingRealm(抽象类)可以实现从缓存中取AuthenticationInfo:
由源代码可以得知AuthenticatingRealm有以下属性:
//用于密码验证,登录的明文密码与加密后的密码是否匹配
private CredentialsMatcher credentialsMatcher;
//使用缓存技术从缓存中获取AuthenticationInfo
private Cache<Object, AuthenticationInfo> authenticationCache;
//是否使用缓存获取AuthenticationInfo
private boolean authenticationCachingEnabled;
//获取名称
private String authenticationCacheName;
==========主要方法介绍============
public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//从缓存中获取AuthenticationInfo
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;
}