最近的工作就是看一下项目的源码,天天看啊看的。。。
今天看到这个方法挖一下源码,然后把他记录下来
@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对象。好了就到这里吧,再往深了扒就自己扒吧,我就扒到这儿了。。。。