序
本文就来讲一讲spring security oauth2的refresh token方式
authorizedGrantTypes
oauth2官方只有4种授权方式,不过spring security oauth2把refresh token也归为authorizedGrantTypes的一种,因此配置的时候只需要这样就把所有方式都支持了
@Configuration
@EnableAuthorizationServer //提供/oauth/authorize,/oauth/token,/oauth/check_token,/oauth/confirm_access,/oauth/error
public class OAuth2ServerConfig extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("demoApp")
.secret("demoAppSecret")
.redirectUris("http://localhost:8081/callback") //新增redirect_uri
.authorizedGrantTypes("authorization_code", "client_credentials", "refresh_token",
"password", "implicit")
.scopes("all")
.resourceIds("oauth2-resource")
.accessTokenValiditySeconds(120)
.refreshTokenValiditySeconds(60);
}
}
配置userDetailsService
要使用refresh_token的话,需要额外配置userDetailsService
@Autowired
private UserDetailsService userDetailsService;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
endpoints.userDetailsService(userDetailsService);
}
否则报错如下
HTTP/1.1 500
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
X-Application-Context: application
Cache-Control: no-store
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 06 Dec 2017 13:35:33 GMT
Connection: close
{"error":"server_error","error_description":"UserDetailsService is required."}
get token
curl -i -d "grant_type=authorization_code&code=uKGjVz&client_id=demoApp&client_secret=demoAppSecret&redirect_uri=http://localhost:8081/callback" -X POST http://localhost:8080/oauth/token
refresh token
curl -i -X POST -u 'demoApp:demoAppSecret' -d 'grant_type=refresh_token&refresh_token=95844d87-f06e-4a4e-b76c-f16c5329e287' http://localhost:8080/oauth/token
调用时access_token,refresh_token均未过期
HTTP/1.1 200
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
X-Application-Context: application
Cache-Control: no-store
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 06 Dec 2017 13:51:47 GMT
{"access_token":"eb45f1d4-54a5-4e23-bf12-31d8d91a902f","token_type":"bearer","refresh_token":"efa96270-18a1-432c-b9e6-77725c0dabea","expires_in":1199,"scope":"all"}
access_token会变,而且expires延长,refresh_token根据设定的过期时间,没有失效则不变
调用时access_token过期,refresh_token未过期
HTTP/1.1 200
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
X-Application-Context: application
Cache-Control: no-store
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 06 Dec 2017 14:03:50 GMT
{"access_token":"a78999d6-614a-45fe-be58-d5e0b6451bdb","token_type":"bearer","refresh_token":"bb2a0165-769d-43b0-a9a5-1331012ede1f","expires_in":119,"scope":"all"}
access_token会变,而且expires延长,refresh_token根据设定的过期时间,没有失效则不变
调用时refresh_token过期
HTTP/1.1 401
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
X-Application-Context: application
Cache-Control: no-store
Pragma: no-cache
WWW-Authenticate: Bearer error="invalid_token", error_description="Invalid refresh token (expired): 95844d87-f06e-4a4e-b76c-f16c5329e287"
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 06 Dec 2017 14:09:57 GMT
{"error":"invalid_token","error_description":"Invalid refresh token (expired): 95844d87-f06e-4a4e-b76c-f16c5329e287"}
小结
- refresh_token必须在过期之前调用才能换新的token
- 只要refresh_token有效,就可以直接用它来换新的access_token(
失效时间为配置文件中指定的值
)