Authentication源码解析
1、获取当前的 Subject. 调用 SecurityUtils.getSubject();
从当前线程的threadLocals属性中获取Subject对象
SecurityUtils
public static Subject getSubject() {
Subject subject = ThreadContext.getSubject();
if (subject == null) {
subject = (new Subject.Builder()).buildSubject();
ThreadContext.bind(subject);
}
return subject;
}
ThreadContext
public static Subject getSubject() {
return (Subject) get(SUBJECT_KEY);
} public static Object get(Object key) {
if (log.isTraceEnabled()) {
String msg = "get() - in thread [" + Thread.currentThread().getName() + "]";
log.trace(msg);
} Object value = getValue(key);
if ((value != null) && log.isTraceEnabled()) {
String msg = "Retrieved value of type [" + value.getClass().getName() + "] for key [" +
key + "] " + "bound to thread [" + Thread.currentThread().getName() + "]";
log.trace(msg);
}
return value;
} private static final ThreadLocal<Map<Object, Object>> resources = new InheritableThreadLocalMap<Map<Object, Object>>();
private static Object getValue(Object key) {
Map<Object, Object> perThreadResources = resources.get();
return perThreadResources != null ? perThreadResources.get(key) : null;
}
ThreadLocal<T>
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
2、Subject 的 login(AuthenticationToken)
登录验证成功后将Subject.authenticated置位true,登录后再登陆时,当前的用户是否已经被认证. 即是否已经登录. 调用 Subject 的 isAuthenticated()
DelegatingSubject
public void login(AuthenticationToken token) throws AuthenticationException {
clearRunAsIdentitiesInternal();
Subject subject = securityManager.login(this, token);
...... this.principals = principals;
this.authenticated = true;
AuthenticatingSecurityManager中调用authenticator.authenticate(),其中authenticator初始化是org.apache.shiro.authc.pam.ModularRealmAuthenticator.ModularRealmAuthenticator
this.authenticator = new ModularRealmAuthenticator();
public AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {
return this.authenticator.authenticate(token);
}
ModularRealmAuthenticator中循环Realms判断
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
assertRealmsConfigured();
Collection<Realm> realms = getRealms();
if (realms.size() == ) {
return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken);
} else {
return doMultiRealmAuthentication(realms, authenticationToken);
}
}
那ModularRealmAuthenticator中循环Realms是何时赋值的呢?Spring创建DefaultSecurityManager对象及属性赋值之后,调用afterRealmsSet()
AuthenticatingSecurityManager
protected void afterRealmsSet() {
super.afterRealmsSet();
if (this.authenticator instanceof ModularRealmAuthenticator) {
((ModularRealmAuthenticator) this.authenticator).setRealms(getRealms());
}
}
下面以单Realm为例,进行doSingleRealmAuthentication解析。
protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) {
if (!realm.supports(token)) {
String msg = "Realm [" + realm + "] does not support authentication token [" +
token + "]. Please ensure that the appropriate Realm implementation is " +
"configured correctly or that the realm accepts AuthenticationTokens of this type.";
throw new UnsupportedTokenException(msg);
}
AuthenticationInfo info = realm.getAuthenticationInfo(token);
if (info == null) {
String msg = "Realm [" + realm + "] was unable to find account data for the " +
"submitted AuthenticationToken [" + token + "].";
throw new UnknownAccountException(msg);
}
return info;
}
realm.getAuthenticationInfo()中主要实现了:
1、调用Realm.doGetAuthenticationInfo(),从数据源中获取用户、密码及相应的密码处理
2、进行数据源获取的密码和登录页面获取密码的比对
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;
}
开发中一般继承Realm,重写doGetAuthenticationInfo。
最后分析下assertCredentialsMatch方法。
protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
CredentialsMatcher cm = getCredentialsMatcher();
if (cm != null) {
if (!cm.doCredentialsMatch(token, info)) {
//not successful - throw an exception to indicate this:
String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";
throw new IncorrectCredentialsException(msg);
}
} else {
throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " +
"credentials during authentication. If you do not wish for credentials to be examined, you " +
"can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");
}
}
根据credentialsMatcher 属性来进行的密码的比对。在定义Realm时根据加密方式定义相应的CredentialsMatcher,默认为SimpleCredentialsMatcher
<bean id="myRealm" class="org.tarena.shiro.realm.MyRealm">
<property name="credentialsMatcher" >
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="MD5"></property>
<property name="hashIterations" value=""></property>
</bean>
</property>
</bean>
Authentication源码解析的更多相关文章
- Spring Security 访问控制 源码解析
上篇 Spring Security 登录校验 源码解析 分析了使用Spring Security时用户登录时验证并返回token过程,本篇分析下用户带token访问时,如何验证用户登录状态及权限问 ...
- Django生命周期 URL ----> CBV 源码解析-------------- 及rest_framework APIView 源码流程解析
一.一个请求来到Django 的生命周期 FBV 不讨论 CBV: 请求被代理转发到uwsgi: 开始Django的流程: 首先经过中间件process_request (session等) 然后 ...
- Shiro源码解析-Session篇
上一篇Shiro源码解析-登录篇中提到了在登录验证成功后有对session的处理,但未详细分析,本文对此部分源码详细分析下. 1. 分析切入点:DefaultSecurityManger的login方 ...
- Okhttp3源码解析(5)-拦截器RetryAndFollowUpInterceptor
### 前言 回顾: [Okhttp的基本用法](https://www.jianshu.com/p/8e404d9c160f) [Okhttp3源码解析(1)-OkHttpClient分析](htt ...
- Spring Security 解析(七) —— Spring Security Oauth2 源码解析
Spring Security 解析(七) -- Spring Security Oauth2 源码解析 在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因 ...
- .Net Core 认证系统之Cookie认证源码解析
接着上文.Net Core 认证系统源码解析,Cookie认证算是常用的认证模式,但是目前主流都是前后端分离,有点鸡肋但是,不考虑移动端的站点或者纯管理后台网站可以使用这种认证方式.注意:基于浏览器且 ...
- AspNetCore3.1_Secutiry源码解析_1_目录
文章目录 AspNetCore3.1_Secutiry源码解析_1_目录 AspNetCore3.1_Secutiry源码解析_2_Authentication_核心项目 AspNetCore3.1_ ...
- AspNetCore3.1_Secutiry源码解析_2_Authentication_核心对象
系列文章目录 AspNetCore3.1_Secutiry源码解析_1_目录 AspNetCore3.1_Secutiry源码解析_2_Authentication_核心项目 AspNetCore3. ...
- AspNetCore3.1_Secutiry源码解析_3_Authentication_Cookies
系列文章目录 AspNetCore3.1_Secutiry源码解析_1_目录 AspNetCore3.1_Secutiry源码解析_2_Authentication_核心流程 AspNetCore3. ...
随机推荐
- 【转】python requests库添加自定义cookie的方法
requests库是个很方便的爬虫,相关文档已经很详细了.不过我今天在爬网页时,有一个网站是在脚本中添加cookie的,但我向requests.cookies里添加cookie费了不少周折.尝试了多个 ...
- Unity 2018 Game Development in 24 Hours Sams Teach Yourself 3rd Edition
最新的Unity2018自学教材,如果新入坑Unity,直接从2018开始看吧! 点击下载提取码:tngj
- HttpWebrequest使用的注意点
HttpWebrequest使用的注意点 1.HttpWebrequest相关属性的设置以及默认连接数量限制 System.Net.ServicePointManager.DefaultConnect ...
- laravel 通过ftp上传的时候报错 Use of undefined constant FTP_BINARY - assumed 'FTP_BINARY
用Laravel中的filesystems里面的ftp上传文件时报错.在windows上开发,文件上传的时候碰到上面的问题,搜了些资料,发现是php7的ftp拓展默认未开启. filesystems是 ...
- 使用HttpClient访问WebHook
代码: import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.c ...
- Flutter BottomNavigationBar 组件
BottomNavigationBar 是底部导航条,可以让我们定义底部 Tab 切换,bottomNavigationBar是 Scaffold 组件的参数. BottomNavigationBar ...
- 获取IFC构件的位置数据、方向数据
获取IFC构件的位置数据.方向数据 std::map<int, shared_ptr<BuildingEntity>> map_buildingEntity = b_model ...
- osg编译日志
1>------ 已启动全部重新生成: 项目: ZERO_CHECK, 配置: Debug x64 ------1> Checking Build System1> CMake do ...
- 我非要捅穿这 Neutron(二)上层资源模型篇
目录 文章目录 目录 Neutron 的资源模型 Network 运营商网络和租户网络 创建运营商网络 创建租户网络 创建外部网络 Network 小结 Subnet IP 核心网络服务 Subnet ...
- winform使用委托和事件在窗体之间传值
定义委托和事件,并且触发这个事件 //定义委托 public delegate void ShowOutStockDelegate(List<OutStockResultDto> outS ...