有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Spring Oauth2自定义异常处理程序

在基于Spring Security Oauth2的身份验证中,当客户端发送需要刷新的访问令牌时,DefaultTokenServices类抛出InvalidTokenException(参见第235行):

https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/provider/token/DefaultTokenServices.java

发生这种情况时的输出类似于:

{"error":"invalid_token","error_description":"Invalid access token: a0cb5ab9-7281-46bd-a9a2-796a04a906c9"
}

我想更改此输出,但我迷路了。其他一些答案建议设置一个自定义的异常渲染器,但这也不起作用,在这些情况下,我的自定义异常渲染器从未被调用

还有一种叫做异常翻译器的东西,但在任何情况下都没有被调用

我的spring配置的一部分:

<bean id="clientAuthenticationEntryPoint"
      class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
    <property name="typeName" value="Basic"/>
    <property name="exceptionRenderer" ref="myExceptionRenderer" />
</bean>


<bean id="oauthAuthenticationEntryPoint"
      class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
      <property name="exceptionRenderer" ref="myExceptionRenderer" />
      <property name="exceptionTranslator" ref="listyOauthExceptionTranslator" />
</bean>

<bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" >
 <property name="exceptionRenderer" ref="myExceptionRenderer" />
 <property name="exceptionTranslator" ref="myExceptionTranslator" />
</bean>

<bean id="myExceptionRenderer" class="com.example.exceptions.MyOauth2ExceptionRenderer" />

<bean id="myExceptionTranslator" class="com.example.exceptions.MyOauth2ExceptionTranslator" />

异常渲染器:

public class MyExceptionRenderer implements OAuth2ExceptionRenderer {

@Override
public void handleHttpEntityResponse(HttpEntity<?> responseEntity, ServletWebRequest webRequest) throws Exception {
    System.out.println("Thrown exception");
}

}

我还添加了一个定制的异常映射器,它应该可以获取所有的异常,但是因为我假设它是另一个servlet,所以在这种情况下它实际上不起作用

@Provider
public class GenericExceptionMapper implements ExceptionMapper<Throwable> {

@Override 
public Response toResponse(Throwable ex) {
    System.out.println("MAPPING EXCEPTION");
    return Response.status(200).entity().build();
}
}

我可以捕捉到AuthenticationException的情况,但不能捕捉到任何InvalidTokenException

有什么帮助吗?Spring实际上在哪里捕获这个InvalidTokenException,如何设置它以便提供自定义输出


共 (4) 个答案

  1. # 1 楼答案

    InvalidTokenException扩展ClientAuthenticationException。因此,您可以通过扩展ClientAuthenticationException来创建自己的异常,并抛出这个异常,而不是InvalidTokenException

    public class CustomException extends ClientAuthenticationException {
    
        public CustomException(String msg, Throwable t) {
            super(msg, t);
        }
    
        public CustomException(String msg) {
            super(msg);
        }
        @Override
        public String getOAuth2ErrorCode() {
            return "my_custom_exception";
        }
    }
    

    就像

    throw new CustomException("Invalid access token: " + accessTokenValue);
    

    在InvalidTokenException引发的错误中

     {"error":"invalid_token","error_description":"Invalid access token: a0cb5ab9-7281-46bd-a9a2-796a04a906c9"}
    

    invalid_token由InvalidTokenException的getOAuth2ErrorCode()方法返回,Invalid access token: a0cb5ab9-7281-46bd-a9a2-796a04a906c9是抛出异常时给出的消息

    如果你扔

     throw new CustomException("This is my custom exception");
    

    错误将显示为

    {"error":"my_custom_exception","error_description":"This is my custom exception"}
    

    my_custom_exception来自CustomExceptiongetOAuth2ErrorCode()

  2. # 3 楼答案

    答案并不是真正提供自定义实现,自定义响应将是代码中的一个点,在这里我可以访问默认响应,并可以发送POJO而不是POJO,例如,如果您想将error_description更改为error_info或其他任何内容,或者您可能想向响应添加更多变量。这个解决方案确实存在,但我认为实施起来很痛苦,至少可以这么说,因为我从here复制了它:

    This problem has been solved. Follow the workaround below:

    1. Extend OAuth2Exception to a new class, such as CustomOAuth2Exception. In the custom class, add some specific properties.
    2. custom DefaultWebResponseExceptionTranslator and register the custom translator in AuthorizationServerConfiguration.
    3. custom two jackson serializers annotated in OAuth2Exception and annotated your CustomOAuth2Exception with the two custom serializers.
    4. use ObjectMapper to override initial serializers with custom serializers.
  3. # 4 楼答案

    为了压倒

    {"error":"invalid_token","error_description":"Invalid access token: a0cb5ab9-7281-46bd-a9a2-796a04a906c9"
    }
    

    您需要继承ResourceServerConfigurerAdapter 并覆盖public void configure(最终资源服务器安全配置器配置)

    示例代码

    package com.org.security;
    
    import org.springframework.http.ResponseEntity;
    import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
    import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;
    import org.springframework.stereotype.Component;
    
    
    @Component
    public class CustomWebResponseExceptionTranslator extends DefaultWebResponseExceptionTranslator {
    
        /**
         * Modify OAuth2.0 Error Response
         * @param e
         * @return ResponseEntity<OAuth2Exception>
         * @throws Exception
         */
    
        @Override
        public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception {
            ResponseEntity responseEntity = super.translate(e);
            OAuth2Exception auth2Exception = (OAuth2Exception)responseEntity.getBody();
            if (auth2Exception != null) {
                auth2Exception.addAdditionalInformation("data", null);
                auth2Exception.addAdditionalInformation("message", auth2Exception.getMessage());
                auth2Exception.addAdditionalInformation("statusCode", String.valueOf(auth2Exception.getHttpErrorCode()));
            }
            return new ResponseEntity<OAuth2Exception>(auth2Exception, responseEntity.getHeaders(), responseEntity.getStatusCode());
        }
    }
    
    
    
    
    
    package com.org.security;
    
    import com.org.exception.CustomAuthExceptionEntryPoint;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.http.SessionCreationPolicy;
    import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
    import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
    import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
    import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;
    import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint;
    import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
    import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
    
    
    @Configuration
    @EnableResourceServer
    public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
    
        @Autowired
        private ResourceServerTokenServices tokenServices;
    
        @Autowired
        private WebResponseExceptionTranslator oauth2ResponseExceptionTranslator;
    
        @Override
        public void configure(final ResourceServerSecurityConfigurer config) {
            OAuth2AccessDeniedHandler auth2AccessDeniedHandler = new OAuth2AccessDeniedHandler();
            auth2AccessDeniedHandler.setExceptionTranslator(oauth2ResponseExceptionTranslator);
            OAuth2AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
            authenticationEntryPoint.setExceptionTranslator(oauth2ResponseExceptionTranslator);
            config.tokenServices(tokenServices).accessDeniedHandler(auth2AccessDeniedHandler).authenticationEntryPoint(authenticationEntryPoint);
        }
    
    }