日常笔记---2019年10月31日15:20:01--- 测试Oauth2 refresh

mac2024-05-11  29

测试Oauth2 refresh_token

Your heart is free. Have the courage to follow it.
权限自动续期,获取Access Token Access_Token有默认的有效期,过期后需要用户重新授权才能获得新的Access_Token。本步骤可以实现授权自动续期,避免要求用户再次授权的操作,提升用户体验。 前提: refresh_token在过期之前调用才能请求到新的token。 默认有效时间: 在配置client 端的时候,配置授权类型 authorizedGrantTypes 包含 “refresh_code”。 @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("client_01") .secret("123456") .scopes("read") .autoApprove(true) .authorities("oauth_admin") .authorizedGrantTypes("refresh_token","authorization_code","password","client_credentials");

本地项目请求token的地址:http://localhost:8882/oauth/token 第一次正常获取token结果:

{ "access_token": "627afc96-ced5-4aab-8f92-a3830ad9eae0", "token_type": "bearer", "refresh_token": "4fa139f6-d0bf-443f-942d-f98cb4b7a74d", "expires_in": 43199, "scope": "read" }

请求自动续期操作: 参数

参数是否必须相关解释grant_type必须授权类型,此处操作值应为“refresh_token”client_id必须分配的客户端idclient_secret必须分配的客户端密码refresh_token必须值为上一次请求返回值中"refresh_token“

请求结果如下: 调用refresh_token有以下几种情况:

调用时access_token,refresh_token均未过期调用时access_token过期,refresh_token未过期 此前两种情况,access_token会变,而且expires延长,refresh_token根据设定的过期时间,没有失效则不变。refresh_token过期 报错: {"error":"invalid_token","error_description":"Invalid refresh token (expired): 95844d87-f06e-4a4e-b76c-f16c5329e287"} 测试过程中遇到部分报错记录: <1 如果配置client 时授权类型 authorizedGrantTypes没有包含 “refresh_code”,会出现一下错误: Unauthorized grant type: refresh_token 以下响应结果经过自定义处理: { "success": false, "msg": "Unauthorized grant type: refresh_token", "errorCode": "400", "path": "/oauth/token", "timestamp": "1572507979741" }

<2 报错message: UserDetailsService is required. 具体信息:

2019-10-31 15:53:12.715 INFO 15792 --- [nio-8882-exec-5] o.s.s.o.provider.endpoint.TokenEndpoint : Handling error: IllegalStateException, UserDetailsService is required.

本来是以为在AuthorizationServerConfigurerAdapter配置是不用去进行用户验证的,所以只在WebSecurityConfigurerAdapter 中添加了UserDetailsService的配置,后面经过查询资料发现需要在AuthorizationServerEndpointsConfigurer中配上UserDetailsService。问题解决,原因大概是在进行refresh_token的时候,需要根据token值去重新进行一次用户验证。通过打断点的方式,发现调用了loadUserByUsername方法去进行re-authenticate。 相关源码列下:

@Transactional(noRollbackFor={InvalidTokenException.class, InvalidGrantException.class}) public OAuth2AccessToken refreshAccessToken(String refreshTokenValue, TokenRequest tokenRequest) throws AuthenticationException { if (!supportRefreshToken) { throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue); } OAuth2RefreshToken refreshToken = tokenStore.readRefreshToken(refreshTokenValue); if (refreshToken == null) { throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue); } OAuth2Authentication authentication = tokenStore.readAuthenticationForRefreshToken(refreshToken); if (this.authenticationManager != null && !authentication.isClientOnly()) { // The client has already been authenticated, but the user authentication might be old now, so give it a // chance to re-authenticate. Authentication user = new PreAuthenticatedAuthenticationToken(authentication.getUserAuthentication(), "", authentication.getAuthorities()); user = authenticationManager.authenticate(user); Object details = authentication.getDetails(); authentication = new OAuth2Authentication(authentication.getOAuth2Request(), user); authentication.setDetails(details); } String clientId = authentication.getOAuth2Request().getClientId(); if (clientId == null || !clientId.equals(tokenRequest.getClientId())) { throw new InvalidGrantException("Wrong client for this refresh token: " + refreshTokenValue); } // clear out any access tokens already associated with the refresh // token. tokenStore.removeAccessTokenUsingRefreshToken(refreshToken); if (isExpired(refreshToken)) { tokenStore.removeRefreshToken(refreshToken); throw new InvalidTokenException("Invalid refresh token (expired): " + refreshToken); } authentication = createRefreshedAuthentication(authentication, tokenRequest); if (!reuseRefreshToken) { tokenStore.removeRefreshToken(refreshToken); refreshToken = createRefreshToken(authentication); } OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken); tokenStore.storeAccessToken(accessToken, authentication); if (!reuseRefreshToken) { tokenStore.storeRefreshToken(accessToken.getRefreshToken(), authentication); } return accessToken; }

其中注释已经足以解释为什么需要在AuthorizationServerEndpointsConfigurer中配上UserDetailsService: // The client has already been authenticated, but the user authentication might be old now, so give it a // chance to re-authenticate.

修改配置如下:

@Autowired private UserServiceDetail userServiceDetail; @Override @Primary public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.tokenStore(new InMemoryTokenStore()) .authenticationManager(authenticationManager) .exceptionTranslator(customWebResponseExceptionTranslator) .userDetailsService(userServiceDetail) .allowedTokenEndpointRequestMethods(HttpMethod.POST, HttpMethod.GET); }
最新回复(0)