当用户请求资源服务器的资源时, OAuth2AuthenticationProcessingFilter 拦截
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
ServletException {
final boolean debug = logger.isDebugEnabled();
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
try {
Authentication authentication = tokenExtractor.extract(request);//进入 BearerTokenExtractor
if (authentication == null) {
if (stateless && 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(authenticationDetailsSource.buildDetails(request));
}
Authentication authResult = authenticationManager.authenticate(authentication);
if (debug) {
logger.debug("Authentication success: " + authResult);
}
eventPublisher.publishAuthenticationSuccess(authResult);
SecurityContextHolder.getContext().setAuthentication(authResult);
}
}
catch (OAuth2Exception failed) {
SecurityContextHolder.clearContext();
if (debug) {
logger.debug("Authentication request failed: " + failed);
}
eventPublisher.publishAuthenticationFailure(new BadCredentialsException(failed.getMessage(), failed),
new PreAuthenticatedAuthenticationToken("access-token", "N/A"));
authenticationEntryPoint.commence(request, response,
new InsufficientAuthenticationException(failed.getMessage(), failed));
return;
}
chain.doFilter(request, response);
}
public class BearerTokenExtractor implements TokenExtractor {
private final static Log logger = LogFactory.getLog(BearerTokenExtractor.class);
@Override
public Authentication extract(HttpServletRequest request) {
String tokenValue = extractToken(request);
if (tokenValue != null) {
PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(tokenValue, "");
return authentication;
}
return null;
}
protected String extractToken(HttpServletRequest request) {
// first check the header...
String token = extractHeaderToken(request);
// bearer type allows a request parameter as well
if (token == null) {
logger.debug("Token not found in headers. Trying request parameters.");
token = request.getParameter(OAuth2AccessToken.ACCESS_TOKEN);
if (token == null) {
logger.debug("Token not found in request parameters. Not an OAuth2 request.");
}
else {
request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE, OAuth2AccessToken.BEARER_TYPE);
}
}
return token;
}
protected String extractHeaderToken(HttpServletRequest request) {
Enumeration<String> headers = request.getHeaders("Authorization");
while (headers.hasMoreElements()) { // typically there is only one (most servers enforce that)
String value = headers.nextElement();
if ((value.toLowerCase().startsWith(OAuth2AccessToken.BEARER_TYPE.toLowerCase()))) {
String authHeaderValue = value.substring(OAuth2AccessToken.BEARER_TYPE.length()).trim();
// Add this here for the auth details later. Would be better to change the signature of this method.
request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE,
value.substring(0, OAuth2AccessToken.BEARER_TYPE.length()).trim());
int commaIndex = authHeaderValue.indexOf(',');
if (commaIndex > 0) {
authHeaderValue = authHeaderValue.substring(0, commaIndex);
}
return authHeaderValue;
}
}
return null;
}
}
Authentication authentication = tokenExtractor.extract(request);
这里从request获取读取header里的Authorization对应的token,
String token = extractHeaderToken(request);
如果token为null,再尝试去获取请求参数
token = request.getParameter("access_token");
如果authentication = null,在ExceptionTranslationFilter类捕获到异常,抛出的异常会经过默认的DefaultWebResponseExceptionTranslator 处理然后 Reseponse给Client端,在界面上显示错误信息
Full authentication is required to access this resourceunauthorized
。
我们想让这个错误信息返回是个json,可以这么设置
1.自定义异常转换类
@Slf4j
public class MyWebResponseExceptionTranslator implements WebResponseExceptionTranslator<Map<String, String>> {
@Override
public ResponseEntity<Map<String, String>> translate(Exception e) throws Exception {
Map<String, Object> map = new HashMap<>();
map.put("msg", e.getMessage());
map.put("code", -1);
return new ResponseEntity(map, HttpStatus.METHOD_NOT_ALLOWED);
}
}
2.资源服务器中使得自定义类生效
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
// 定义异常转换类生效
AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
((OAuth2AuthenticationEntryPoint) authenticationEntryPoint).setExceptionTranslator(new Auth2ResponseExceptionTranslator());
resources.authenticationEntryPoint(authenticationEntryPoint);
}
}
此时在界面再请求时返回
{"msg":"Full authentication is required to access this resource","code":-1}
或者另一种方式
1.自定义 MyAuthenticationEntryPoint 类
/**
* 替换掉 ExceptionTranslationFilter 的 authenticationEntryPoint,默认是 OAuth2AuthenticationEntryPoint
*/
@Slf4j
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
log.error(authException.getMessage(), authException);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
PrintWriter out = response.getWriter();
BaseResponse baseResponse = BaseResponse.builder().code(-1).message(authException.getMessage()).build();
out.print(JSON.toJSONString(baseResponse));
}
}
2.资源服务器中使得自定义类生效
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(new MyAuthenticationEntryPoint())
.and()
.authorizeRequests()
.antMatchers("/idx/**").hasAnyAuthority("ADMIN")
.antMatchers("/home/**").hasAnyAuthority("HOME");
}
}
网友评论