Я настроил сервер авторизации Oauth2 с весенней загрузкой в качестве автономного сервера. Он отлично работает для grant_type password
, client_credentials
и т. Д. С включенной JWT Однако, когда я использую grant_type=refresh_token
, сервер авторизации отвечает успешно, даже если срок действия refresh_token
истек, или дважды отправьте refresh_token (настроенный на повторное использование refresh_token
).
Ниже приведен пример вывода консоли почтальона.
Получить токен JWT
Request Headers:
Content-Type:"application/x-www-form-urlencoded"
cache-control:"no-cache"
Postman-Token:"993b222c-6b94-4eb9-b458-36ec5d3a2ed5"
Authorization:"Basic Y2xpZW50XzE6c2VjcmV0"
User-Agent:"PostmanRuntime/7.6.0"
Accept:"*/*"
Host:"localhost:8080"
cookie:"JSESSIONID=25D2C296A51FA2BD39D9C6B5724AC85D"
accept-encoding:"gzip, deflate"
content-length:52
Request Body:
username:"admin"
password:"password"
grant_type:"password"
Response Headers:
Access-Control-Allow-Origin:"*"
Access-Control-Allow-Methods:"POST, PUT, GET, OPTIONS, DELETE"
Access-Control-Allow-Headers:"Authorization, Content-Type"
Access-Control-Max-Age:"3600"
Pragma:"no-cache"
Cache-Control:"no-store"
X-Content-Type-Options:"nosniff"
X-XSS-Protection:"1; mode=block"
X-Frame-Options:"DENY"
Content-Type:"application/json;charset=UTF-8"
Transfer-Encoding:"chunked"
Date:"Sat, 11 May 2019 06:43:42 GMT"
Response Body:
access_token:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTc1OTMwMjIsInVzZXJfbmFtZSI6ImFkbWluIiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiJdLCJqdGkiOiI0MjFiZDJjNC01ODAxLTRiOTktYTk2MS04YzVjNjZiMzA1NjUiLCJjbGllbnRfaWQiOiJjbGllbnRfMSIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSIsInRydXN0Il19.42B_TUfZ5fZAYFZQmSY4smvH_aIH9nsnoOzvMiGs2q0"
token_type:"bearer"
refresh_token:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSIsInRydXN0Il0sImF0aSI6IjQyMWJkMmM0LTU4MDEtNGI5OS1hOTYxLThjNWM2NmIzMDU2NSIsImV4cCI6MTU1NzU5MzAyMiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiJdLCJqdGkiOiI5MGZkMDg5YS0xZmZjLTRkOWItOTk2ZS0zOWMyZmEzM2E1YzkiLCJjbGllbnRfaWQiOiJjbGllbnRfMSJ9.hfZl6p8IBzMjDCJ6UZHB-LVTv4gZJxuRKx_H867i0F4"
expires_in:35999
scope:"read write trust"
jti:"421bd2c4-5801-4b99-a961-8c5c66b30565"
Получить новый токен доступа из списка обновления
Request Headers:
Content-Type:"application/x-www-form-urlencoded"
cache-control:"no-cache"
Postman-Token:"15b00c4d-d9fd-409e-b787-dd14c9fc8a59"
Authorization:"Basic Y2xpZW50XzE6c2VjcmV0"
User-Agent:"PostmanRuntime/7.6.0"
Accept:"*/*"
Host:"localhost:8080"
cookie:"JSESSIONID=25D2C296A51FA2BD39D9C6B5724AC85D"
accept-encoding:"gzip, deflate"
content-length:415
Request Body:
refresh_token:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSIsInRydXN0Il0sImF0aSI6IjQyMWJkMmM0LTU4MDEtNGI5OS1hOTYxLThjNWM2NmIzMDU2NSIsImV4cCI6MTU1NzU5MzAyMiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiJdLCJqdGkiOiI5MGZkMDg5YS0xZmZjLTRkOWItOTk2ZS0zOWMyZmEzM2E1YzkiLCJjbGllbnRfaWQiOiJjbGllbnRfMSJ9.hfZl6p8IBzMjDCJ6UZHB-LVTv4gZJxuRKx_H867i0F4"
grant_type:"refresh_token"
scope:"read"
Response Headers:
Access-Control-Allow-Origin:"*"
Access-Control-Allow-Methods:"POST, PUT, GET, OPTIONS, DELETE"
Access-Control-Allow-Headers:"Authorization, Content-Type"
Access-Control-Max-Age:"3600"
Pragma:"no-cache"
Cache-Control:"no-store"
X-Content-Type-Options:"nosniff"
X-XSS-Protection:"1; mode=block"
X-Frame-Options:"DENY"
Content-Type:"application/json;charset=UTF-8"
Transfer-Encoding:"chunked"
Date:"Sat, 11 May 2019 06:44:02 GMT"
Response Body:
access_token:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTc1OTMwNDIsInVzZXJfbmFtZSI6ImFkbWluIiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiJdLCJqdGkiOiI1YmM5OGM3NC1iZDdlLTQ4MDktYjg5Yi1hOTEwYWZiZDMzOGQiLCJjbGllbnRfaWQiOiJjbGllbnRfMSIsInNjb3BlIjpbInJlYWQiXX0.dF8m_j-1xOnQb4ccPc2YNF77UBTcIIZlFsTi7EO-cfQ"
token_type:"bearer"
refresh_token:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiXSwiYXRpIjoiNWJjOThjNzQtYmQ3ZS00ODA5LWI4OWItYTkxMGFmYmQzMzhkIiwiZXhwIjoxNTU3NTkzMDQyLCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6Ijg5MWFkY2I1LWY1OWYtNDMzMS1iNWFhLTRmMzcxNzU5MDFjZSIsImNsaWVudF9pZCI6ImNsaWVudF8xIn0.gUIZCsBMLIR2K8_WO2v9zwKxE5OYbMqt3UQGIFb3SBs"
expires_in:35999
scope:"read"
jti:"5bc98c74-bd7e-4809-b89b-a910afbd338d"
Повторить попытку с образцом токена обновления (теперь он отвечает sccess, в идеале он должен был ответить недействительным refresh_token)
Request Headers:
Content-Type:"application/x-www-form-urlencoded"
cache-control:"no-cache"
Postman-Token:"53190109-bf08-4b12-a2dd-37216beed103"
Authorization:"Basic Y2xpZW50XzE6c2VjcmV0"
User-Agent:"PostmanRuntime/7.6.0"
Accept:"*/*"
Host:"localhost:8080"
cookie:"JSESSIONID=25D2C296A51FA2BD39D9C6B5724AC85D"
accept-encoding:"gzip, deflate"
content-length:415
Request Body:
refresh_token:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSIsInRydXN0Il0sImF0aSI6IjQyMWJkMmM0LTU4MDEtNGI5OS1hOTYxLThjNWM2NmIzMDU2NSIsImV4cCI6MTU1NzU5MzAyMiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiJdLCJqdGkiOiI5MGZkMDg5YS0xZmZjLTRkOWItOTk2ZS0zOWMyZmEzM2E1YzkiLCJjbGllbnRfaWQiOiJjbGllbnRfMSJ9.hfZl6p8IBzMjDCJ6UZHB-LVTv4gZJxuRKx_H867i0F4"
grant_type:"refresh_token"
scope:"read"
Response Headers:
Access-Control-Allow-Origin:"*"
Access-Control-Allow-Methods:"POST, PUT, GET, OPTIONS, DELETE"
Access-Control-Allow-Headers:"Authorization, Content-Type"
Access-Control-Max-Age:"3600"
Pragma:"no-cache"
Cache-Control:"no-store"
X-Content-Type-Options:"nosniff"
X-XSS-Protection:"1; mode=block"
X-Frame-Options:"DENY"
Content-Type:"application/json;charset=UTF-8"
Transfer-Encoding:"chunked"
Date:"Sat, 11 May 2019 06:44:04 GMT"
Response Body:
access_token:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTc1OTMwNDQsInVzZXJfbmFtZSI6ImFkbWluIiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiJdLCJqdGkiOiIxNjliZjU2NS0yZTQyLTQ5NDktYTcwMC1lMWMxOTg1ZTM2NTkiLCJjbGllbnRfaWQiOiJjbGllbnRfMSIsInNjb3BlIjpbInJlYWQiXX0._hO1doe0FfH_OC4EoRv67vznbToeRvHh_9t2HY5pN0M"
token_type:"bearer"
refresh_token:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiXSwiYXRpIjoiMTY5YmY1NjUtMmU0Mi00OTQ5LWE3MDAtZTFjMTk4NWUzNjU5IiwiZXhwIjoxNTU3NTkzMDQ0LCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6IjQwN2E0ZGM1LWU4M2YtNDVlYS04ZDdjLWMwNmQyZGEzNDQ5MyIsImNsaWVudF9pZCI6ImNsaWVudF8xIn0.02WvhOH3Y5vx9-NTtppupBePWKTUHHejYkbLQ3iCMEA"
expires_in:35999
scope:"read"
jti:"169bf565-2e42-4949-a700-e1c1985e3659"
Рабочий пример без JWT
Получить токен
Request Headers:
Content-Type:"application/x-www-form-urlencoded"
cache-control:"no-cache"
Postman-Token:"b1ef5f14-30bf-4df5-9a1b-57eedc8ad25c"
Authorization:"Basic Y2xpZW50XzE6c2VjcmV0"
User-Agent:"PostmanRuntime/7.6.0"
Accept:"*/*"
Host:"localhost:8080"
cookie:"JSESSIONID=25D2C296A51FA2BD39D9C6B5724AC85D"
accept-encoding:"gzip, deflate"
content-length:52
Request Body:
username:"admin"
password:"password"
grant_type:"password"
Response Headers:
Access-Control-Allow-Origin:"*"
Access-Control-Allow-Methods:"POST, PUT, GET, OPTIONS, DELETE"
Access-Control-Allow-Headers:"Authorization, Content-Type"
Access-Control-Max-Age:"3600"
Pragma:"no-cache"
Cache-Control:"no-store"
X-Content-Type-Options:"nosniff"
X-XSS-Protection:"1; mode=block"
X-Frame-Options:"DENY"
Content-Type:"application/json;charset=UTF-8"
Transfer-Encoding:"chunked"
Date:"Sat, 11 May 2019 06:35:49 GMT"
Response Body:
access_token:"3e026c95-2b67-47a0-a305-0e7e4bb2690d"
token_type:"bearer"
refresh_token:"5bdfb8e2-3248-400f-b860-13f1318d9a34"
expires_in:36000
scope:"read write trust"
Жетон обновления
Request Headers:
Content-Type:"application/x-www-form-urlencoded"
cache-control:"no-cache"
Postman-Token:"ed9ac62f-ddad-4c42-9286-9fbd82cb1414"
Authorization:"Basic Y2xpZW50XzE6c2VjcmV0"
User-Agent:"PostmanRuntime/7.6.0"
Accept:"*/*"
Host:"localhost:8080"
cookie:"JSESSIONID=25D2C296A51FA2BD39D9C6B5724AC85D"
accept-encoding:"gzip, deflate"
content-length:86
Request Body:
refresh_token:"5bdfb8e2-3248-400f-b860-13f1318d9a34"
grant_type:"refresh_token"
scope:"read"
Response Headers:
Access-Control-Allow-Origin:"*"
Access-Control-Allow-Methods:"POST, PUT, GET, OPTIONS, DELETE"
Access-Control-Allow-Headers:"Authorization, Content-Type"
Access-Control-Max-Age:"3600"
Pragma:"no-cache"
Cache-Control:"no-store"
X-Content-Type-Options:"nosniff"
X-XSS-Protection:"1; mode=block"
X-Frame-Options:"DENY"
Content-Type:"application/json;charset=UTF-8"
Transfer-Encoding:"chunked"
Date:"Sat, 11 May 2019 06:43:11 GMT"
Response Body:
access_token:"73dc3f14-38f4-419d-b457-1233108100a5"
token_type:"bearer"
refresh_token:"ad48ff61-f8c3-41ac-abb2-08dc212f3c14"
expires_in:35999
scope:"read"
Повторить попытку с тем же токеном обновления (теперь получен ошибочный токен с ошибкой)
Request Headers:
Content-Type:"application/x-www-form-urlencoded"
cache-control:"no-cache"
Postman-Token:"98fe827b-168b-45d1-bd6a-ee6cbb27a098"
Authorization:"Basic Y2xpZW50XzE6c2VjcmV0"
User-Agent:"PostmanRuntime/7.6.0"
Accept:"*/*"
Host:"localhost:8080"
cookie:"JSESSIONID=25D2C296A51FA2BD39D9C6B5724AC85D"
accept-encoding:"gzip, deflate"
content-length:86
Request Body:
refresh_token:"5bdfb8e2-3248-400f-b860-13f1318d9a34"
grant_type:"refresh_token"
scope:"read"
Response Headers:
Access-Control-Allow-Origin:"*"
Access-Control-Allow-Methods:"POST, PUT, GET, OPTIONS, DELETE"
Access-Control-Allow-Headers:"Authorization, Content-Type"
Access-Control-Max-Age:"3600"
Pragma:"no-cache"
Cache-Control:"no-store"
X-Content-Type-Options:"nosniff"
X-XSS-Protection:"1; mode=block"
X-Frame-Options:"DENY"
Content-Type:"application/json;charset=UTF-8"
Transfer-Encoding:"chunked"
Date:"Sat, 11 May 2019 06:43:13 GMT"
Connection:"close"
Response Body:
error:"invalid_grant"
error_description:"Invalid refresh token: 5bdfb8e2-3248-400f-b860-13f1318d9a34"
Вот мой AuthConfig.java
@Configuration
@EnableAuthorizationServer
@EnableConfigurationProperties(AuthorizationServerProperties.class)
@Import({ AuthorizationServerTokenServicesConfiguration.class, AuthorizationServerEndpointsConfiguration.class })
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private DataSource dataSource;
@Autowired
private AuthorizationServerProperties authorization;
@Autowired(required = false)
private TokenStore tokenStore;
@Autowired(required = false)
private AccessTokenConverter tokenConverter;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource).passwordEncoder(passwordEncoder).build();
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.passwordEncoder(passwordEncoder);
if (this.authorization.getCheckTokenAccess() != null) {
security.checkTokenAccess(this.authorization.getCheckTokenAccess());
}
if (this.authorization.getTokenKeyAccess() != null) {
security.tokenKeyAccess(this.authorization.getTokenKeyAccess());
}
if (this.authorization.getRealm() != null) {
security.realm(this.authorization.getRealm());
}
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager).userDetailsService(userDetailsService)
.reuseRefreshTokens(false);
if (this.tokenConverter != null) {
endpoints.accessTokenConverter(this.tokenConverter);
}
if (this.tokenStore != null) {
endpoints.tokenStore(this.tokenStore);
}
}
}
application.yml
spring:
application:
name: auth-server
security:
oauth2:
authorization:
check-token-access: "isAuthenticated()"
jwt:
key-value: 12345
Любые идеи для решения проблемы приветствуются.