使用OAuth2自定义Spring Security的auth错误

时间:2017-08-31 15:37:07

标签: java security spring-boot spring-security spring-security-oauth2

我想知道是否可以自定义以下授权错误:

sh '''
cd path/to/your/submodule
git pull $ZUUL_URL/$ZUUL_PROJECT +$ZUUL_REF:refs/heads/zuul
'''

我在用户请求没有权限时得到它。我想将它定制为与Spring Boot错误非常相似:

{
  "error": "unauthorized",
  "error_description": "Full authentication is required to access this resource"
}

可能吗?

非常感谢。

4 个答案:

答案 0 :(得分:6)

我明白了:)

https://stackoverflow.com/a/37132751/2520689

我需要创建一个实现“AuthenticationEntryPoint”的新类,如下所示:

public class AuthExceptionEntryPoint implements AuthenticationEntryPoint
{
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException arg2) throws IOException, ServletException
    {
        final Map<String, Object> mapBodyException = new HashMap<>() ;

        mapBodyException.put("error"    , "Error from AuthenticationEntryPoint") ;
        mapBodyException.put("message"  , "Message from AuthenticationEntryPoint") ;
        mapBodyException.put("exception", "My stack trace exception") ;
        mapBodyException.put("path"     , request.getServletPath()) ;
        mapBodyException.put("timestamp", (new Date()).getTime()) ;

        response.setContentType("application/json") ;
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED) ;

        final ObjectMapper mapper = new ObjectMapper() ;
        mapper.writeValue(response.getOutputStream(), mapBodyException) ;
    }
}

并将其添加到我的ResourceServerConfigurerAdapter实现中:

@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter
{   
    @Override
    public void configure(HttpSecurity http) throws Exception
    {
        http.exceptionHandling().authenticationEntryPoint(new AuthExceptionEntryPoint()) ;

    }
}

你可以找到我的GitHub项目,它实现了你需要的一切:

https://github.com/pakkk/custom-spring-security

答案 1 :(得分:0)

使用Oauth2,接受的答案对我不起作用。经过研究,exception translator solution可以正常工作。

基本上,您需要创建一个WebResponseExceptionTranslator并将其注册为您的异常翻译器。

首先,创建一个WebResponseExceptionTranslator bean:

@Slf4j
@Configuration
public class Oauth2ExceptionTranslatorConfiguration {

    @Bean
    public WebResponseExceptionTranslator oauth2ResponseExceptionTranslator() {
        return new DefaultWebResponseExceptionTranslator() {

            @Override
            public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception {

                ResponseEntity<OAuth2Exception> responseEntity = super.translate(e);
                OAuth2Exception body = responseEntity.getBody();
                HttpStatus statusCode = responseEntity.getStatusCode();

                body.addAdditionalInformation("timestamp", dateTimeFormat.format(clock.instant()))
                body.addAdditionalInformation("status", body.getHttpErrorCode().toString())
                body.addAdditionalInformation("message", body.getMessage())
                body.addAdditionalInformation("code", body.getOAuth2ErrorCode().toUpperCase())

                HttpHeaders headers = new HttpHeaders();
                headers.setAll(responseEntity.getHeaders().toSingleValueMap());
                // do something with header or response
                return new ResponseEntity<>(body, headers, statusCode);
            }
        };
    }

}

现在,您需要更改Oauth2配置以注册bean WebResponseExceptionTranslator

@Slf4j
@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private ClientDetailsServiceBuilder builder;

    @Autowired
    private WebResponseExceptionTranslator oauth2ResponseExceptionTranslator;

    @Autowired
    private UserDetailsService userDetailsService;


    @Override
    public void configure(ClientDetailsServiceConfigurer clients) {
        clients.setBuilder(builder);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();

        tokenEnhancerChain.setTokenEnhancers(
                Arrays.asList(tokenEnhancer(), accessTokenConverter()));

        endpoints.tokenStore(tokenStore())
                .tokenEnhancer(tokenEnhancerChain)
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService)
                .exceptionTranslator(oauth2ResponseExceptionTranslator);

    }

}

最终结果将是:

{
    "error": "unauthorized",
    "error_description": "Full authentication is required to access this resource",
    "code": "UNAUTHORIZED",
    "message": "Full authentication is required to access this resource",
    "status": "401",
    "timestamp": "2018-06-28T23:55:28.86Z"
}

您可以看到我没有从OAuth2Exception的原始正文中删除errorerror_description。我建议维护它们,因为这两个字段遵循OAuth2规范。有关更多详细信息,请参见the RFCOAuth2 API definitions

您还可以自定义结果:覆盖errorerror_description(仅调用addAdditionalInformation),使用instance of标识特定的异常以返回不同的json结果,等等。但是也有一些限制:如果您想将某个字段定义为integer,我认为这是不可能的,因为addAdditionalInformation方法只接受String作为类型。

答案 2 :(得分:0)

故事短片https://github.com/melardev/JavaSpringBootOAuth2JwtCrudPagination.git

在阅读@pakkk响应后,我不同意,所以我决定尝试自己的方式,但同样失败了,所以我决定看看Spring Security源代码本身,这是怎么回事: 有一个非常早就被调用的过滤器,即OAuth2AuthenticationProcessingFilter。 如果引发异常,此过滤器将尝试从标头中提取JWT。 它的authenticationEntryPoint.commence()(@pakk在这里) 我尝试添加一个过滤器来检查Jwt无效或存在时是否调用了它,但是没有,因此,添加自定义过滤器以更改响应将不起作用。 然后,我查看了OAuth2AuthenticationProcessingFilter的配置位置,发现它是在ResourceServerSecurityConfigurer :: configure(HttpSecurity http)上设置的。 如此说来,让我们看看如何融入流程。 事实证明这很容易,因为您将在资源服务器应用程序中扩展ResourceServerConfigurerAdapter类:

@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
// ....
}

您继续操作并覆盖:

@Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        super.configure(resources);
}

如您所见,是的!您可以访问ResourceServerSecurityConfigurer,那么现在呢? 好吧,让我们用我们的替换默认的入口点:

@Autowired
    private AuthenticationEntryPoint oauthEntryPoint;
@Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        super.configure(resources);

        resources.authenticationEntryPoint(oauthEntryPoint);
    }

有关示例的完整源代码,请参见: https://github.com/melardev/JavaSpringBootOAuth2JwtCrudPagination.git

没有此步骤,至少对我来说这是行不通的,@ pakkk提供的响应对我不起作用,我在调试器上进行了检查,默认情况下使用的入口点不是我们的入口点,即使使用: / p>

http.and().exceptionHandling().authenticationEntryPoint(oauthEntryPoint)

这是我测试的第一件事,要使其正常运行,您必须直接从ResourceServerSecurityConfigurer类中更改入口点。

这是我的切入点:请注意,我正在发送属于我自己的类的ErrorResponse对象,因此我可以完全控制响应:

@Component
public class OAuthEntryPoint implements AuthenticationEntryPoint {

    @Autowired
    ObjectMapper mapper;

    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        ServletServerHttpResponse res = new ServletServerHttpResponse(httpServletResponse);
        res.setStatusCode(HttpStatus.FORBIDDEN);
        res.getServletResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        res.getBody().write(mapper.writeValueAsString(new ErrorResponse("You must authenticated")).getBytes());
    }
}

答案 3 :(得分:-1)

我认为您可以使用@ControllerAdvice来捕获未经授权的异常,然后根据您的期望格式化响应并将其返回。像这样:

@ResponseBody
@ExceptionHandler(CustomException.class)
@ResponseStatus(value=HttpStatus.UNAUTHORIZED, reason="Exception message")
public JsonResponse unAuthorised(HttpServletRequest request, Exception ex) {
    return new JsonResponse("ERROR", 401, "Unauthorised Request");
}

希望得到这个帮助。