权限管理框架之Shiro 的使用和原理(二)

今天分析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相结合的无状态登录方案,敬请期待!

猜你喜欢

转载自blog.csdn.net/nandao158/article/details/108574519