美文网首页
【Spring Cloud】08-OAuth2资源服务器Chec

【Spring Cloud】08-OAuth2资源服务器Chec

作者: Y了个J | 来源:发表于2020-02-27 21:43 被阅读0次

当用户请求资源服务器的资源时, 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");
    }
}

相关文章

网友评论

      本文标题:【Spring Cloud】08-OAuth2资源服务器Chec

      本文链接:https://www.haomeiwen.com/subject/qxgxhhtx.html