今天分析Shiro的源码,承接上一篇:
//核心登录源码
Subject userSubject=SecurityUtils.getSubject();//取得用户唯一userSubject
AuthenticationToken shiroToken=new UsernamePasswordToken(userName,clientId);//存储信息
subject.login(shiroToken);//shiro登录
1、点击这个方法 SecurityUtils.getSubject()
public static Subject getSubject() {
Subject subject = ThreadContext.getSubject();//来自线程引用容器,进行点击
if (subject == null) {
subject = (new Builder()).buildSubject();
ThreadContext.bind(subject);
}
return subject;
}
2、点击连续点击:
//相关静态变量
public static final String SUBJECT_KEY = ThreadContext.class.getName() + "_SUBJECT_KEY";
private static final ThreadLocal<Map<Object, Object>> resources = new ThreadContext.InheritableThreadLocalMap();
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;
}
//resources 就是 ThreadLocal<Map<Object, Object>> 线程副本
private static Object getValue(Object key) {
Map<Object, Object> perThreadResources = (Map)resources.get();
return perThreadResources != null ? perThreadResources.get(key) : null;
}
//从线程副本里取出返回值
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
最后来自线程副本resoucres,它是ThreadContxt的静态变量,resources.get()得到当前线程的线程副本,从线程副本中拿到以ThreadContxt实例为key对应的value值,是个泛型值,这里泛型是一个Map<object,object>类型。
3、存储用户相关信息
AuthenticationToken shiroToken=new UsernamePasswordToken(userName,clientId);
4、shiro 登录:subject.login(shiroToken);
我发现有一篇文章分析的挺好,可以参考一下:
https://blog.csdn.net/fcs_learner/article/details/79283936
5、 subject.login(shiroToken)方法执行后会自动进入一个继承了 AuthorizingRealm 类的 doGetAuthenticationInfo 方法:
/**
* 验证当前登录的Subject
* LoginController.login()中 调Subject.login()时执行此方法
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
System.out.println("进入登录验证接口-------");
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
String userName = token.getUsername().trim();
String clientId = String.valueOf(token.getPassword());
logger.info("获取模拟验证登录时传递的密码参数,clientId,clientId={}",clientId);
UserVO userVO =permissionService.getUserAndPermissionByClientId(clientId);
SecurityUtils.getSubject().getSession().setAttribute(Constants.SESSION_USER_INFO, userVO);
return new SimpleAuthenticationInfo(userName, clientId, getName());
}
shiro 简单使用流程如此,下一篇,我们从微服务的登录入口,全局实战解析 jwt、token、shiro相结合的无状态登录方案,敬请期待!