最近的工作就是看一下项目的源码,天天看啊看的。。。
今天看到这个方法挖一下源码,然后把他记录下来
@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;
}
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。