2017年8月14日---阶段性工作总结(sp se框架中的一个简单方法源码分析)

最近的工作就是看一下项目的源码,天天看啊看的。。。

今天看到这个方法挖一下源码,然后把他记录下来

	@GetMapping("/authenticate")
	@Timed
	public String isAuthenticated(HttpServletRequest request) {
		log.debug("REST request to check if the current user is authenticated");
		return request.getRemoteUser();//认证用户返回用户名,如果不是认证用户则返回null
	}

然后我很好奇啊,怎么HttpServletRequest request对象的getRemoteUser方法能够知道

check if the current user is authenticated
有时候感觉用英文真的比用中文能解释清楚。
于是我点进getRemoteUser方法进一步查看,得到他是HttpServletRequest接口中定义的一个方法
这无可厚非,我能理解,但是当我点开他的实现类时,我就不淡定了
我怎么知道用的哪个实现类?或者换句话说,系统怎么知道用哪个实现类来处理用户请求?
比如用户打开浏览器就直接访问刚才那个接口,程序是怎么知道用哪个实现类去处理的?

因为我用的是sp se做权限校验的,根据经验我也确定,他一定是用的第四个实现类
但是为什么就用来第四个实现类了呢?
后来我问了一下高手,他解释说,具体的他也不太清楚,因为他不怎么用sp se框架,一直用的shiro
但是他说:“估计sp se的入口应该是个filter,在filter里面他对这个方法进行了替换或者实现”。
我觉得他说的很对,一定是sp se框架将所有的http请求包装成了Securityhttp请求!!!
于是这道坎我就过去了,继续快乐的继续看下面的源码。
他调用了一个本类中的另一个方法,继续
继续看getContext()方法

发现是strategy对象调用了getContext()方法,继续看源码,发现这个类里面有一个静态代码块,
代码块中有一个这个initialize()方法,这个方法初始化了SecurityContextHolderStrategy
也就是strategy而且默认是
MODE_THREADLOCAL的
    private static void initialize() {
        if(!StringUtils.hasText(strategyName)) {
            strategyName = "MODE_THREADLOCAL";
        }

        if(strategyName.equals("MODE_THREADLOCAL")) {
            strategy = new ThreadLocalSecurityContextHolderStrategy();
        } else if(strategyName.equals("MODE_INHERITABLETHREADLOCAL")) {
            strategy = new InheritableThreadLocalSecurityContextHolderStrategy();
        } else if(strategyName.equals("MODE_GLOBAL")) {
            strategy = new GlobalSecurityContextHolderStrategy();
        } else {
            try {
                Class<?> clazz = Class.forName(strategyName);
                Constructor<?> customStrategy = clazz.getConstructor(new Class[0]);
                strategy = (SecurityContextHolderStrategy)customStrategy.newInstance(new Object[0]);
            } catch (Exception var2) {
                ReflectionUtils.handleReflectionException(var2);
            }
        }

        ++initializeCount;
    }
这还没完呢,这只是实例化一个strategy对象,继续点方法实现
找到接口
先看第三个实现
其他两个实现我没看,这个第三个实现是一个典型的threadLocal类的用法
package org.springframework.security.core.context;

import org.springframework.util.Assert;

final class ThreadLocalSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
    private static final ThreadLocal contextHolder = new ThreadLocal();

    ThreadLocalSecurityContextHolderStrategy() {
    }

    public void clearContext() {
        contextHolder.remove();
    }

    public SecurityContext getContext() {
        SecurityContext ctx = (SecurityContext)contextHolder.get();
        if(ctx == null) {
            ctx = this.createEmptyContext();
            contextHolder.set(ctx);
        }

        return ctx;
    }

    public void setContext(SecurityContext context) {
        Assert.notNull(context, "Only non-null SecurityContext instances are permitted");
        contextHolder.set(context);
    }

    public SecurityContext createEmptyContext() {
        return new SecurityContextImpl();
    }
}
这里他只所以能直接
SecurityContext ctx = (SecurityContext)contextHolder.get();
这么用,是因为他ThreadLocal是直接从当前线程id里面去值,他是拿当前线程的id当作key,去存储值。这样即使你不去给他的get方法传递参数,他也能够获取到value。
好了,一条线已经点到头了,都快给我自己点懵圈了。。。

刚才我们点的是getContext()方法,现在我们继续点后面的方法,看看后面的方法做了啥。。。
然后发现后面的方法也没做啥,就是从前面的方法的返回对象SecurityContext中获取Authentication对象。
好了就到这里吧,再往深了扒就自己扒吧,我就扒到这儿了。。。。



















發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章