如何包装OAuth2异常?

ale*_*lek 5 java spring json oauth spring-security-oauth2

我们有一个使用的rest API Spring OAuth2.用户通过身份验证后,所有JSON响应都采用以下格式:

{"code" : 12345, "data" : "..." }
Run Code Online (Sandbox Code Playgroud)

但是,身份验证失败的JSON响应与上述格式不一致,因为它由Spring处理.

例如,如果凭据不正确,客户端将获得带有JSON响应的HTTP状态代码400,如下所示:

{"error": "invalid_grant", "error_description": "Bad credentials" }
Run Code Online (Sandbox Code Playgroud)

如果用户帐户被锁定,客户端将获得具有JSON响应的HTTP状态代码400,如下所示

{"error":"invalid_grant","error_description":"User account is locked"}
Run Code Online (Sandbox Code Playgroud)

所有这一切都是因为Spring TokenEndpoint.handleException()正在处理与/ oauth/token相关的异常

我想更改OAuth2失败的JSON响应以遵循第一种格式.

这是我迄今为止尝试过的但没有成功:

  1. 使用ControllerAdvice最高precendence为了与使用@ExceptionHandler描述这里
  2. 实施OAuth2ExceptionRenderer描述这里
  3. 实现ExceptionMapper
  4. 添加了一个新的ObjectMapper,扩展了StdSerializer.虽然我的objectmapper已初始化,但它不用于序列化异常.也许是因为Spring直接调用MappingJackson2HttpMessageConverter而且我的应用程序中似乎有这个类的几个实例.

任何上述方法或新方法的任何帮助将受到高度赞赏.

我没有尝试过这种方法,因为我无法更改现有客户端的上下文路径.

Man*_*kus 1

如果您想处理身份验证过程,您可以设置自己的自定义身份验证管理器

<oauth:authorization-server
    client-details-service-ref="clientDetails" token-services-ref="tokenServices"
    user-approval-handler-ref="userApprovalHandler">
    <oauth:authorization-code />
    <oauth:implicit />
    <oauth:refresh-token />
    <oauth:client-credentials />
    <oauth:password authentication-manager-ref="customAuthenticationManager" />
</oauth:authorization-server>

<authentication-manager id="customAuthenticationManager"
    xmlns="http://www.springframework.org/schema/security">
    <authentication-provider ref="customAuthenticationProvider" />
</authentication-manager>

<bean id="customAuthenticationProvider"
    class="com.any.CustomAuthenticationProvider">
</bean>
Run Code Online (Sandbox Code Playgroud)

创建实现的自定义身份验证提供程序AuthenticationProvider

public class UserAuthenticationProvider implements AuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
        String username = auth.getName();
        String password = token.getCredentials().toString();
        User user = userService.loadByUsername(username);
        if(user.isLocked){
            throw new UserLockedException("User is locked");
        }
        if(another.something.bad.happened){
            throw new AnotherSomethingBadHappenedException("Error");
        }

        // setup authorities
        //...

        return new UsernamePasswordAuthenticationToken(user, password, authorities);
    }


}
Run Code Online (Sandbox Code Playgroud)

现在您有了自己的异常,通过使用 ExceptionMapper,您可以将身份验证过程中引发的异常转换为自定义响应消息。

您可以创建的另一个自定义是在授权过程中,通过创建扩展的自定义类ApprovalStoreUserApprovalHandler

public class CustomUserApprovalHandler extends ApprovalStoreUserApprovalHandler {

    // stripped

    @Override
    public AuthorizationRequest checkForPreApproval(AuthorizationRequest authorizationRequest,
            Authentication userAuthentication) {

        ClientDetails client = clientDetailsService
                            .loadClientByClientId(authorizationRequest.getClientId());
        // here, you have the client and the user
        // you can do any checking here and throw any exception
        authorizationRequest.setApproved(approved);
        return authorizationRequest;
    }
}
Run Code Online (Sandbox Code Playgroud)

为该类创建 bean 定义

<bean id="userApprovalHandler"
    class="com.any.CustomUserApprovalHandler">
        <property name="approvalStore" ref="approvalStore" />
        <property name="requestFactory" ref="oAuth2RequestFactory" />
        <property name="clientDetailsService" ref="clientDetails" />
        <property name="useApprovalStore" value="true" />
    </bean>
Run Code Online (Sandbox Code Playgroud)