Spring Security-覆盖默认的TokenEndpoint方法(/ oauth / token)

时间:2018-12-31 03:31:33

标签: spring spring-security spring-security-oauth2

我计划在新项目中实施oauth2 & JWT。除了用户名,密码和grant_type之外,在授予access_tokenrefresh_token之前,我还有其他几个字段需要验证。因此,我计划覆盖默认的TokenEndpoint's postAccessToken方法的实现。如果可以,我应该注意哪些事项?重写默认实现是否正确?例如,下面是TokenEndpoint的postAccessToken签名。

public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
....
}

在这里,在到达postAccessToken方法之前,只有spring-security构造了Principal对象。

我的端点看起来像这样,没有Principal对象(不确定将来会引入什么问题)。

@PostMapping("/token")
public ResponseEntity token(@Valid @RequestBody LoginModel loginModel, @RequestParam Map<String, String> parameters) {
....
}

spring-security本身并没有什么其他好处,因此,如果我覆盖此/ token端点,我应该照顾所有什么事情?

1 个答案:

答案 0 :(得分:0)

Apart from username, password & grant_type, I am having a few another fields to validate before granting the access_token and refresh_token.

由于您还有其他字段需要验证密码授予类型,因此它不再是密码授予类型。因此,建议不要通过修改TokenEndpoint来修改默认行为。您可以做的是编写自定义TokenGranter

看看ResourceOwnerPasswordTokenGranter,它是密码授予类型的实现。通过假设您可以像下面这样写一个CustomResourceOwnerPasswordTokenGranter

public class CustomResourceOwnerPasswordTokenGranter extends ResourceOwnerPasswordTokenGranter {

private static final String GRANT_TYPE = "custom-password";

private final AuthenticationManager authenticationManager;

public CustomResourceOwnerPasswordTokenGranter(AuthenticationManager authenticationManager,
        AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
    this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
}

protected CustomResourceOwnerPasswordTokenGranter(AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices,
        ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, String grantType) {
    super(tokenServices, clientDetailsService, requestFactory, grantType);
    this.authenticationManager = authenticationManager;
}

@Override
protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {

    Map<String, String> parameters = new LinkedHashMap<String, String>(tokenRequest.getRequestParameters());
    String username = parameters.get("username");
    String password = parameters.get("password");

    // You can use parameters.get to read your custom parameter fields

    ...

}

此处要注意的重要事项是GRANT_TYPE的变量值和getOAuth2Authentication的实现。

最后,您使用以下Java配置注册CustomResourceOwnerPasswordTokenGranter实现。

public TokenGranter tokenGranter() {

        ClientDetailsService clientDetails = clientDetailsService;
        AuthorizationServerTokenServices tokenServices = tokenServices();
        AuthorizationCodeServices authorizationCodeServices = authorizationCodeServices();
        OAuth2RequestFactory requestFactory = requestFactory();

        List<TokenGranter> tokenGranters = new ArrayList<TokenGranter>();

        tokenGranters.add(new AuthorizationCodeTokenGranter(tokenServices, authorizationCodeServices,
                clientDetails, requestFactory));
        tokenGranters.add(new RefreshTokenGranter(tokenServices, clientDetails, requestFactory));
        tokenGranters.add(new ImplicitTokenGranter(tokenServices, clientDetails, requestFactory));
        tokenGranters.add(new ClientCredentialsTokenGranter(tokenServices, clientDetails, requestFactory));
        tokenGranters.add(new ResourceOwnerPasswordTokenGranter(authenticationManager, tokenServices,
                    clientDetails, requestFactory));
        tokenGranters.add(new CustomTokenGranter(authenticationManager, tokenServices(), clientDetailsService,
                requestFactory));
        // Register the CustomResourceOwnerPasswordTokenGranter here
        tokenGranters.add(new CustomResourceOwnerPasswordTokenGranter(authenticationManager, tokenServices,
                    clientDetails, requestFactory));

        return new CompositeTokenGranter(tokenGranters);
}

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

    endpoints
            .tokenServices(tokenServices())
            .tokenStore(tokenStore())
            .tokenEnhancer(tokenEnhancer())
            .authorizationCodeServices(authorizationCodeServices())
            .userApprovalHandler(userApprovalHandler())
            .authenticationManager(authenticationManager)
            .requestFactory(requestFactory())
            .tokenGranter(tokenGranter());
}

最后,您可以使用参数/oauth/tokengrant_type=custom-password&username=<Username>&password=<Password>&customFieldOne=1&customFieldTwo=2发送POST请求并调用您的自定义实现。