Чтобы добавить и добавить дополнительную информацию о токене, лучше и стандартнее использовать TokenEnhancer. Это интерфейс, который дает вам возможность улучшить токен доступа перед его сохранением. Ниже приведен пример скелета:
@Configuration
@EnableAuthorizationServer
class SecurityOAuth2AutorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.....
.tokenEnhancer(tokenEnhancer())
.approvalStoreDisabled();
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
....
}
@Bean
public TokenEnhancer tokenEnhancer(){
return new YourTokenEnhancer ();
}
}
class YourTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
User user = (User) authentication.getPrincipal();
final Map<String, Object> additionalInfo = new HashMap<>();
additionalInfo.put("yourAdditionalKey", "yourAdditionalValue");
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
return accessToken;
}
}
Обновление
учитывая ваше сообщение, если вы хотите добавить информацию в заголовок, вы можете использовать перехватчик и связать его с классом org.springframework.security.oauth2.provider.endpoint.TokenEndpoint, который является классом, который вы вызываете для получения токена и добавления услышать вашу дополнительную информацию.
Однако я не одобряю этот подход в пользу более стандартного способа и рассматриваю возможность использования TokenEnhancer, который является стандартным способом добавления дополнительной информации на ваш токен.
Обновление
учитывая комментарии, которые я могу предложить, чтобы реализовать вашу логику аудита с аспектом на вашем сервере аутентификации, аспект может быть таким, как показано ниже:
@Aspect
@Component
class AuditLogger {
@AfterReturning("execution(* org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(..))")
public void aspect(JoinPoint joinPoint) {
Map<String, String> params = (Map<String, String>) joinPoint.getArgs()[1];
System.out.println("success");
System.out.println(params);
// your audit logic in case of successful login
}
@AfterThrowing(value = "execution(* org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(..))", throwing = "error")
public void error(JoinPoint joinPoint, Exception error) {
System.out.println(error);
Map<String, String> params = (Map<String, String>) joinPoint.getArgs()[1];
System.out.println("error");
System.out.println(params);
// your audit logic in case of failure login
}
}
Я предлагаю использовать аспект вместо реализации пользовательских компонентов Spring Security, потому что: во-первых, аудит является сквозной задачей, и аспект является одним из лучших решений для достижения этой цели, а затем, потому что настраивайте Spring Security, особенно для Oauth2 - это сложная задача, и я не советую ее, поскольку мой опыт слишком сложен, и усилия не окупаются, протокол очень сложен, и заполнить все варианты использования - задача. С аспектом, который делает аудит для вас в правильной точке, это лучший вариант для вас.
Я построил аспект, который выполняет аудит по методу TokenEndpoint.postAccessToken
, то есть коду безопасности Spring oAuht2, который генерирует токен
Код вашего интереса к платформе Spring ниже:
@FrameworkEndpoint
public class TokenEndpoint extends AbstractEndpoint {
....
@RequestMapping(value = "/oauth/token", method=RequestMethod.POST)
public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam
Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
if (!(principal instanceof Authentication)) {
throw new InsufficientAuthenticationException(
"There is no client authentication. Try adding an appropriate authentication filter.");
}
String clientId = getClientId(principal);
ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId);
TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);
if (clientId != null && !clientId.equals("")) {
// Only validate the client details if a client authenticated during this
// request.
if (!clientId.equals(tokenRequest.getClientId())) {
// double check to make sure that the client ID in the token request is the same as that in the
// authenticated client
throw new InvalidClientException("Given client ID does not match authenticated client");
}
}
if (authenticatedClient != null) {
oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient);
}
if (!StringUtils.hasText(tokenRequest.getGrantType())) {
throw new InvalidRequestException("Missing grant type");
}
if (tokenRequest.getGrantType().equals("implicit")) {
throw new InvalidGrantException("Implicit grant type not supported from token endpoint");
}
if (isAuthCodeRequest(parameters)) {
// The scope was requested or determined during the authorization step
if (!tokenRequest.getScope().isEmpty()) {
logger.debug("Clearing scope of incoming token request");
tokenRequest.setScope(Collections.<String> emptySet());
}
}
if (isRefreshTokenRequest(parameters)) {
// A refresh token has its own default scopes, so we should ignore any added by the factory here.
tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE)));
}
OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
if (token == null) {
throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType());
}
return getResponse(token);
}
....
}
Я надеюсь, что это может помочь вам