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源码解析的更多相关文章

  1. Spring Security 访问控制 源码解析

    上篇 Spring Security 登录校验 源码解析  分析了使用Spring Security时用户登录时验证并返回token过程,本篇分析下用户带token访问时,如何验证用户登录状态及权限问 ...

  2. Django生命周期 URL ----> CBV 源码解析-------------- 及rest_framework APIView 源码流程解析

    一.一个请求来到Django 的生命周期   FBV 不讨论 CBV: 请求被代理转发到uwsgi: 开始Django的流程: 首先经过中间件process_request (session等) 然后 ...

  3. Shiro源码解析-Session篇

    上一篇Shiro源码解析-登录篇中提到了在登录验证成功后有对session的处理,但未详细分析,本文对此部分源码详细分析下. 1. 分析切入点:DefaultSecurityManger的login方 ...

  4. Okhttp3源码解析(5)-拦截器RetryAndFollowUpInterceptor

    ### 前言 回顾: [Okhttp的基本用法](https://www.jianshu.com/p/8e404d9c160f) [Okhttp3源码解析(1)-OkHttpClient分析](htt ...

  5. Spring Security 解析(七) —— Spring Security Oauth2 源码解析

    Spring Security 解析(七) -- Spring Security Oauth2 源码解析   在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因 ...

  6. .Net Core 认证系统之Cookie认证源码解析

    接着上文.Net Core 认证系统源码解析,Cookie认证算是常用的认证模式,但是目前主流都是前后端分离,有点鸡肋但是,不考虑移动端的站点或者纯管理后台网站可以使用这种认证方式.注意:基于浏览器且 ...

  7. AspNetCore3.1_Secutiry源码解析_1_目录

    文章目录 AspNetCore3.1_Secutiry源码解析_1_目录 AspNetCore3.1_Secutiry源码解析_2_Authentication_核心项目 AspNetCore3.1_ ...

  8. AspNetCore3.1_Secutiry源码解析_2_Authentication_核心对象

    系列文章目录 AspNetCore3.1_Secutiry源码解析_1_目录 AspNetCore3.1_Secutiry源码解析_2_Authentication_核心项目 AspNetCore3. ...

  9. AspNetCore3.1_Secutiry源码解析_3_Authentication_Cookies

    系列文章目录 AspNetCore3.1_Secutiry源码解析_1_目录 AspNetCore3.1_Secutiry源码解析_2_Authentication_核心流程 AspNetCore3. ...

随机推荐

  1. SuperWebSocket实现服务端和WebSocket4Net实现客户端

    SuperWebSocket实现服务端和WebSocket4Net实现客户端具体实现如下: SuperWebSocket实现服务端 注:本作者是基于vs2019 enterprise版本,所有项目均为 ...

  2. h2的时间类型和函数

    H2时间类型: (时间)TIME: 格式为 hh:mm:ss.对应到Java类型:java.sql.Time. (日期)DATE: 格式为 yyyy-MM-dd.对应到Java类型: java.sql ...

  3. C# mvc后台传过来的list 怎么在js使用

    var arr= JSON.parse('@Html.Raw(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize( ...

  4. oracle根据sqlID查找相对应的sql语句

    转: 根据sqlID查找相对应的sql语句 2019-07-25 14:47:20 猛豪 阅读数 567更多 分类专栏: 数据库   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议 ...

  5. 我的一个PLSQL存储过程【我】 改版,加入日志表

    创建日志表sql: -- Create table create table PROCEDURE_LOG ( ID ) not null, NAME ), CODE NUMBER, MSG ), IN ...

  6. 获取Excel中的图片

    如下图,上传要获取这里面的图片,而又不能直接选择,怎么办呢? 1.首先复制一份Excel文件命名copy.xlsx 2.修改copy.xlsx文件的后缀名变成copy.rar 3.解压copy.rar ...

  7. Spring Boot 使用YAML配置

    YAML是JSON的一个超集,可以非常方便地将外部配置以层次结构形式存储起来.当项目的类路径中有SnakeYAML库(spring-boot-starter中已经被包含)时,SpringApplica ...

  8. VS2010配置OpenGL开发环境(转)

    OpenGL(Open Graphics Library)是一个跨编程语言.跨平台的专业图形程序接口.OpenGL是SGI公司开发的一套计算机图形处理系统,是图形硬件的软件接口,任何一个OpenGL应 ...

  9. java使用Sonic 算法对音频变速不变声、变调、调整音量

    依赖库:https://github.com/waywardgeek/sonic 基础库:Sonic.java /* Sonic library Copyright 2010, 2011 Bill C ...

  10. [Log4j使用教程] JavaSE/JavaEE/SpringMVC中使用Log4j

    要想使用Log4j, 首先需要下载到Log4j的jar, Download: http://www.apache.org/dyn/closer.cgi/logging/log4j/1.2.17/log ...