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. ...
随机推荐
- Java实现视频网站的视频上传、视频转码、及视频播放功能(ffmpeg)
视频网站中提供的在线视频播放功能,播放的都是FLV格式的文件,它是Flash动画文件,可通过Flash制作的播放器来播放该文件.项目中用制作的player.swf播放器. 多媒体视频处理工具FFmpe ...
- JVM 类加载器命名空间深度解析与实例分析
一.创建Sample 1.创建实例 public class MyPerson { private MyPerson myPerson; public void setMyPerson(Object ...
- 《浅谈F5健康检查常用的几种方式》—那些你应该知道的知识(二)
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/sinat_17736151/articl ...
- IM 简介
LayIM - 打造属于你自己的网页聊天系统http://layim.layui.com/ 瓜子IM智能客服系统的数据架构设计(整理自现场演讲) - 知乎https://zhuanlan.zhihu. ...
- Mac OS docker挂载文件夹
sudo docker run -p 3306:3306 --name mysql -v /var/run/docker.sock:/var/run/docker.sock -v ~/mysql/co ...
- c代码审查软件
1. Coccinelle http://coccinelle.lip6.fr/
- Linux系统调优——系统整体运行状态排查(七)
(1).vmstat vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的整体状态值,包括服务器的CPU使用率,MEM内存使用,VMSwap虚拟内存交换情况,IO读写 ...
- 123457123456#0#-----com.tym.niuniuChengYu05--前拼后广--最牛成语tym
com.tym.niuniuChengYu05--前拼后广--最牛成语tym
- shell脚本中执行mysql sql脚本文件并传递参数
1 shell 文件内容替换 sed是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换.删除.新增.选取等特定工作,下面先了解一下sed的用法. 调用sed命 ...
- Swift4.0复习泛型
1.泛型的基本使用: /// 定义了一个泛型结构体MyStruct, /// 其泛型形参为T struct MyStruct<T> { /// 用泛型T定义存储式成员属性t var t ...