一、解析查找 access_token
1、OAuth2AuthenticationProcessingFilter.tokenExtractor
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
boolean debug = logger.isDebugEnabled();
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
try {
Authentication authentication = this.tokenExtractor.extract(request);
if (authentication == null) {
if (this.stateless && this.isAuthenticated()) {
if (debug) {
logger.debug("Clearing security context.");
}
SecurityContextHolder.clearContext();
}
if (debug) {
logger.debug("No token in request, will continue chain.");
}
} else {
request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, authentication.getPrincipal());
if (authentication instanceof AbstractAuthenticationToken) {
AbstractAuthenticationToken needsDetails = (AbstractAuthenticationToken)authentication;
needsDetails.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
**Authentication authResult = this.authenticationManager.authenticate(authentication);**
if (debug) {
logger.debug("Authentication success: " + authResult);
}
this.eventPublisher.publishAuthenticationSuccess(authResult);
SecurityContextHolder.getContext().setAuthentication(authResult);
}
} catch (OAuth2Exception var9) {
SecurityContextHolder.clearContext();
if (debug) {
logger.debug("Authentication request failed: " + var9);
}
this.eventPublisher.publishAuthenticationFailure(new BadCredentialsException(var9.getMessage(), var9), new PreAuthenticatedAuthenticationToken("access-token", "N/A"));
this.authenticationEntryPoint.commence(request, response, new InsufficientAuthenticationException(var9.getMessage(), var9));
return;
}
chain.doFilter(request, response);
}
调用的方法如下,
protected String extractToken(HttpServletRequest request) {
String token = this.extractHeaderToken(request);
if (token == null) {
logger.debug("Token not found in headers. Trying request parameters.");
token = request.getParameter("access_token");
if (token == null) {
logger.debug("Token not found in request parameters. Not an OAuth2 request.");
} else {
request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE, "Bearer");
}
}
return token;
}
可以看出,两种方式取得token,一个时header的"Authorization"字段,一个时请求参数"access_token"。
这样,我们就需要在5号过滤器之前,给请求参数添加一个token。
自定义一个HttpServletRequest包装类:
/**
* 自定义HttpServletRequest包装类,设置addParameter()方法。
* @author sola
*/
public class ParameterRequestWrapper extends HttpServletRequestWrapper {
private Map params = new HashMap();
@SuppressWarnings("unchecked")
public ParameterRequestWrapper(HttpServletRequest request) {
// 将request交给父类,以便于调用对应方法的时候,将其输出,其实父亲类的实现方式和第一种new的方式类似
super(request);
//将参数表,赋予给当前的Map以便于持有request中的参数
this.params.putAll(request.getParameterMap());
}
//重载一个构造方法
public ParameterRequestWrapper(HttpServletRequest request , Map extendParams) {
this(request);
//这里将扩展参数写入参数表
addAllParameters(extendParams);
}
@Override
public String getParameter(String name) {//重写getParameter,代表参数从当前类中的map获取
String[]values = params.get(name);
if(values == null || values.length == 0) {
return null;
}
return values[0];
}
@Override
public String[] getParameterValues(String name) {//同上
return params.get(name);
}
public void addAllParameters(MapotherParams) {//增加多个参数
for(Map.Entryentry : otherParams.entrySet()) {
addParameter(entry.getKey() , entry.getValue());
}
}
public void addParameter(String name , Object value) {//增加参数
if(value != null) {
if(value instanceof String[]) {
params.put(name , (String[])value);
}else if(value instanceof String) {
params.put(name , new String[] {(String)value});
}else {
params.put(name , new String[] {String.valueOf(value)});
}
}
}
然后自定义一个过滤器(项目中是从cookie中取出的token,OAuth2.0不支持直接对cookie进行鉴权):
/**
* @author sola
*/
@Slf4j
public class HttpServletRequestCrossFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
log.info("\n\n" +
"****************************************************************\n" +
"****************** HttpServletRequestCrossFilter ***********\n" +
"****************************************************************\n");
ParameterRequestWrapper parameterRequestWrapper = new ParameterRequestWrapper(request);
Cookie accessToken = CookieUtils.getCookieByName(request, "access_token");
log.info("cookie:{}", accessToken);
if (accessToken != null && (accessToken.getValue()) != null && (accessToken.getValue()) != "") {
String token = accessToken.getValue();
log.info("token:{}", token);
//从cookie中取出token,把它设置为请求参数;还有另一种方式,设置请求头Authorization = bearer+空格+token
parameterRequestWrapper.addParameter("access_token",token);
} else {
log.info("没有token");
}
//把自定义的request传入过滤器链,进入下一个过滤器
filterChain.doFilter(parameterRequestWrapper, response);
}
}
把自定义的过滤器放入过滤器链,5号过滤器之前:
@Override
public void configure(HttpSecurity http) throws Exception {
//省略其他设置
...........
http.addFilterAfter(new HttpServletRequestCrossFilter(),HeaderWriterFilter.class);
}
OK,搞定。