我计划在新项目中实施oauth2 & JWT
。除了用户名,密码和grant_type之外,在授予access_token
和refresh_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端点,我应该照顾所有什么事情?
答案 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/token
向grant_type=custom-password&username=<Username>&password=<Password>&customFieldOne=1&customFieldTwo=2
发送POST请求并调用您的自定义实现。