当前位置:   article > 正文

Spring Security OAuth2实现多用户类型认证、刷新Token_spring security oauth2 刷新token

spring security oauth2 刷新token

原本的OAuth2登录支持用户名密码登录,现在还想支持另外用id号码和密码登录。但是OAuth2默认提供的UserDetailsService只允许传入一个参数:

想要实现多种用户登录,是不是可以考虑loadUserByUsername方法携带多个参数呢?

接下来记录一下实现步骤:

  1. 新增interface CustomUserDetailsServiceInter 继承原来的UserDetailsService,新增自定义方法loadUserByUsername

  1. public interface CustomUserDetailsServiceInter extends UserDetailsService {
  2. CustomUser loadUserByUsername(String var1, String var2) throws UsernameNotFoundException;
  3. }
  1. 然后根据自己需要实现CustomUserDetailsServiceInter接口的方法,这里就不放出来了

  1. @Slf4j
  2. @Component
  3. public class CustomUserDetailsService implements CustomUserDetailsServiceInter {
  4.     @Override
  5. public CustomUser loadUserByUsername(String username, String idCard) throws UsernameNotFoundException {
  6.         // 根据自己需要进行实现
  7. // 1.获取用户
  8. // 2.获取用户可访问权限信息
  9. // 3.构造UserDetails信息并返回
  10.         return userDetails;
  11.     }
  12. }
  1. 从现在开始,所有需要用到userDetailsService的,全部都要替换成自定义CustomUserDetailsService。比如WebSecurityConfigurer、AuthServerConfigurer

  1. 复制org.springframework.security.authentication.dao.DaoAuthenticationProvider的代码,自定义 CustomerDaoAuthenticationProvider,然后进行修改retrieveUser()方法,其他不需要动

  1. public class CustomerDaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
  2. private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
  3. private PasswordEncoder passwordEncoder;
  4. private volatile String userNotFoundEncodedPassword;
  5. private CustomUserDetailsService userDetailsService;
  6. private UserDetailsPasswordService userDetailsPasswordService;
  7. public CustomerDaoAuthenticationProvider() {
  8. setPasswordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder());
  9. }
  10. @Override
  11. @SuppressWarnings("deprecation")
  12. protected void additionalAuthenticationChecks(UserDetails userDetails,
  13. UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
  14. if (authentication.getCredentials() == null) {
  15. this.logger.debug("Failed to authenticate since no credentials provided");
  16. throw new BadCredentialsException(this.messages
  17. .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
  18. }
  19. String presentedPassword = authentication.getCredentials().toString();
  20. String password = userDetails.getPassword();
  21. boolean matches = this.passwordEncoder.matches(presentedPassword, password);
  22. if (!matches) {
  23. this.logger.debug("Failed to authenticate since password does not match stored value");
  24. throw new BadCredentialsException(this.messages
  25. .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
  26. }
  27. }
  28. @Override
  29. protected void doAfterPropertiesSet() {
  30. Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
  31. }
  32. /*@Override
  33. protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
  34. throws AuthenticationException {
  35. prepareTimingAttackProtection();
  36. try {
  37. UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username, authentication.getDetails());
  38. if (loadedUser == null) {
  39. throw new InternalAuthenticationServiceException(
  40. "UserDetailsService returned null, which is an interface contract violation");
  41. }
  42. return loadedUser;
  43. } catch (UsernameNotFoundException ex) {
  44. mitigateAgainstTimingAttack(authentication);
  45. throw ex;
  46. } catch (InternalAuthenticationServiceException ex) {
  47. throw ex;
  48. } catch (Exception ex) {
  49. throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
  50. }
  51. }*/
  52. @Override
  53. protected Authentication createSuccessAuthentication(Object principal, Authentication authentication,
  54. UserDetails user) {
  55. boolean upgradeEncoding = this.userDetailsPasswordService != null
  56. && this.passwordEncoder.upgradeEncoding(user.getPassword());
  57. if (upgradeEncoding) {
  58. String presentedPassword = authentication.getCredentials().toString();
  59. String newPassword = this.passwordEncoder.encode(presentedPassword);
  60. user = this.userDetailsPasswordService.updatePassword(user, newPassword);
  61. }
  62. return super.createSuccessAuthentication(principal, authentication, user);
  63. }
  64. private void prepareTimingAttackProtection() {
  65. if (this.userNotFoundEncodedPassword == null) {
  66. this.userNotFoundEncodedPassword = this.passwordEncoder.encode(USER_NOT_FOUND_PASSWORD);
  67. }
  68. }
  69. private void mitigateAgainstTimingAttack(UsernamePasswordAuthenticationToken authentication) {
  70. if (authentication.getCredentials() != null) {
  71. String presentedPassword = authentication.getCredentials().toString();
  72. this.passwordEncoder.matches(presentedPassword, this.userNotFoundEncodedPassword);
  73. }
  74. }
  75. /**
  76. * Sets the PasswordEncoder instance to be used to encode and validate passwords. If
  77. * not set, the password will be compared using
  78. * {@link PasswordEncoderFactories#createDelegatingPasswordEncoder()}
  79. *
  80. * @param passwordEncoder must be an instance of one of the {@code PasswordEncoder}
  81. * types.
  82. */
  83. public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
  84. Assert.notNull(passwordEncoder, "passwordEncoder cannot be null");
  85. this.passwordEncoder = passwordEncoder;
  86. this.userNotFoundEncodedPassword = null;
  87. }
  88. protected PasswordEncoder getPasswordEncoder() {
  89. return this.passwordEncoder;
  90. }
  91. public void setUserDetailsService(CustomUserDetailsService userDetailsService) {
  92. this.userDetailsService = userDetailsService;
  93. }
  94. protected CustomUserDetailsService getUserDetailsService() {
  95. return this.userDetailsService;
  96. }
  97. public void setUserDetailsPasswordService(UserDetailsPasswordService userDetailsPasswordService) {
  98. this.userDetailsPasswordService = userDetailsPasswordService;
  99. }
  100. protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
  101. this.prepareTimingAttackProtection();
  102. Map<String, String> map = (Map<String, String>) authentication.getDetails(); // 自定义添加
  103. try {
  104. String userIdCard = map.get("idCard"); // 自定义添加
  105. UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username, userIdCard);
  106. if (loadedUser == null) {
  107. throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation");
  108. } else {
  109. return loadedUser;
  110. }
  111. } catch (UsernameNotFoundException var4) {
  112. this.mitigateAgainstTimingAttack(authentication);
  113. throw var4;
  114. } catch (InternalAuthenticationServiceException var5) {
  115. throw var5;
  116. } catch (Exception var6) {
  117. throw new InternalAuthenticationServiceException(var6.getMessage(), var6);
  118. }
  119. }
  120. }

记得将自定义的CustomerDaoAuthenticationProvider中的userDetailsService替换成自定义的CustomUserDetailsService

  1. 到WebSecurityConfig配置上面的CustomAuthenticationProvider

  1. @Bean(name="customAuthenticationProvider")
  2. public AuthenticationProvider customAuthenticationProvider() {
  3. CustomerDaoAuthenticationProvider customAuthenticationProvider= new CustomerDaoAuthenticationProvider();
  4. customAuthenticationProvider.setUserDetailsService(userDetailsService);
  5. customAuthenticationProvider.setHideUserNotFoundExceptions(false);
  6. customAuthenticationProvider.setPasswordEncoder(passwordEncoder);
  7. return customAuthenticationProvider;
  8. }
  9. @Override
  10. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  11. auth.authenticationProvider(customAuthenticationProvider());
  12. }
  1. 可以去获取token试试了

获取access_token请求(/oauth/token)

请求所需参数:client_id、client_secret、grant_type、username、password 这些是默认的,可以用需要的idCard替换username

  1. 现在去请求刷新Token

刷新token请求(/oauth/token)

请求所需参数:grant_type、refresh_token、client_id、client_secret其中grant_type为固定值:grant_type=refresh_token

会发现怎样也刷新不了,因为刷新Token时用的还是原版的UserDetailsService,执行的还是单个参数的loadUserByUsername,所以下面要重新自定义相关类来替换掉

  1. 复制org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper 自定义 CustomUserDetailsByNameServiceWrapper 在 loadUserDetails() 方法添加自定义的idCard

  1. public class CustomUserDetailsByNameServiceWrapper<T extends Authentication> implements
  2. AuthenticationUserDetailsService<T>, InitializingBean {
  3. private CustomUserDetailsService userDetailsService = null;
  4. /**
  5. * Constructs an empty wrapper for compatibility with Spring Security 2.0.x's method
  6. * of using a setter.
  7. */
  8. public CustomUserDetailsByNameServiceWrapper() {
  9. // constructor for backwards compatibility with 2.0
  10. }
  11. /**
  12. * Constructs a new wrapper using the supplied
  13. * {@link org.springframework.security.core.userdetails.UserDetailsService} as the
  14. * service to delegate to.
  15. *
  16. * @param userDetailsService the UserDetailsService to delegate to.
  17. */
  18. public CustomUserDetailsByNameServiceWrapper(final CustomUserDetailsService userDetailsService) {
  19. Assert.notNull(userDetailsService, "userDetailsService cannot be null.");
  20. this.userDetailsService = userDetailsService;
  21. }
  22. /**
  23. * Check whether all required properties have been set.
  24. *
  25. * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
  26. */
  27. public void afterPropertiesSet() {
  28. Assert.notNull(this.userDetailsService, "UserDetailsService must be set");
  29. }
  30. /**
  31. * Get the UserDetails object from the wrapped UserDetailsService implementation
  32. */
  33. public UserDetails loadUserDetails(T authentication) throws UsernameNotFoundException {
  34. // ----------添加自定义的内容----------
  35. AbstractAuthenticationToken principal = (AbstractAuthenticationToken) authentication.getPrincipal();
  36. Map<String,String> map = (Map<String, String>) principal.getDetails();
  37. String userIdCard = map.get("idCard");
  38. // ----------添加自定义的内容----------
  39. return this.userDetailsService.loadUserByUsername(authentication.getName(), userIdCard); // 使用自定义的userDetailsService
  40. }
  41. /**
  42. * Set the wrapped UserDetailsService implementation
  43. *
  44. * @param aUserDetailsService The wrapped UserDetailsService to set
  45. */
  46. public void setUserDetailsService(CustomUserDetailsService aUserDetailsService) {
  47. this.userDetailsService = aUserDetailsService;
  48. }
  49. }
  1. 复制 org.springframework.security.oauth2.provider.token.DefaultTokenServices 到自定义的 CustomTokenServices 然后修改refreshAccessToken() 方法的if (this.authenticationManager != null && !authentication.isClientOnly()) 这里面的内容

  1. public class CustomTokenServices implements AuthorizationServerTokenServices, ResourceServerTokenServices,
  2. ConsumerTokenServices, InitializingBean {
  3. private int refreshTokenValiditySeconds = 60 * 60 * 24 * 30; // default 30 days.
  4. private int accessTokenValiditySeconds = 60 * 60 * 12; // default 12 hours.
  5. private boolean supportRefreshToken = false;
  6. private boolean reuseRefreshToken = true;
  7. private TokenStore tokenStore;
  8. private ClientDetailsService clientDetailsService;
  9. private TokenEnhancer accessTokenEnhancer;
  10. private AuthenticationManager authenticationManager;
  11. /**
  12. * Initialize these token services. If no random generator is set, one will be created.
  13. */
  14. public void afterPropertiesSet() throws Exception {
  15. Assert.notNull(tokenStore, "tokenStore must be set");
  16. }
  17. @Transactional
  18. public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {
  19. OAuth2AccessToken existingAccessToken = tokenStore.getAccessToken(authentication);
  20. OAuth2RefreshToken refreshToken = null;
  21. if (existingAccessToken != null) {
  22. if (existingAccessToken.isExpired()) {
  23. if (existingAccessToken.getRefreshToken() != null) {
  24. refreshToken = existingAccessToken.getRefreshToken();
  25. // The token store could remove the refresh token when the
  26. // access token is removed, but we want to
  27. // be sure...
  28. tokenStore.removeRefreshToken(refreshToken);
  29. }
  30. tokenStore.removeAccessToken(existingAccessToken);
  31. }
  32. else {
  33. // Re-store the access token in case the authentication has changed
  34. tokenStore.storeAccessToken(existingAccessToken, authentication);
  35. return existingAccessToken;
  36. }
  37. }
  38. // Only create a new refresh token if there wasn't an existing one
  39. // associated with an expired access token.
  40. // Clients might be holding existing refresh tokens, so we re-use it in
  41. // the case that the old access token
  42. // expired.
  43. if (refreshToken == null) {
  44. refreshToken = createRefreshToken(authentication);
  45. }
  46. // But the refresh token itself might need to be re-issued if it has
  47. // expired.
  48. else if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
  49. ExpiringOAuth2RefreshToken expiring = (ExpiringOAuth2RefreshToken) refreshToken;
  50. if (System.currentTimeMillis() > expiring.getExpiration().getTime()) {
  51. refreshToken = createRefreshToken(authentication);
  52. }
  53. }
  54. OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
  55. tokenStore.storeAccessToken(accessToken, authentication);
  56. // In case it was modified
  57. refreshToken = accessToken.getRefreshToken();
  58. if (refreshToken != null) {
  59. tokenStore.storeRefreshToken(refreshToken, authentication);
  60. }
  61. return accessToken;
  62. }
  63. @Transactional(noRollbackFor={InvalidTokenException.class, InvalidGrantException.class})
  64. public OAuth2AccessToken refreshAccessToken(String refreshTokenValue, TokenRequest tokenRequest)
  65. throws AuthenticationException {
  66. if (!supportRefreshToken) {
  67. throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue);
  68. }
  69. OAuth2RefreshToken refreshToken = tokenStore.readRefreshToken(refreshTokenValue);
  70. if (refreshToken == null) {
  71. throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue);
  72. }
  73. OAuth2Authentication authentication = tokenStore.readAuthenticationForRefreshToken(refreshToken);
  74. if (this.authenticationManager != null && !authentication.isClientOnly()) {
  75. /*// The client has already been authenticated, but the user authentication might be old now, so give it a
  76. // chance to re-authenticate.
  77. Authentication user = new PreAuthenticatedAuthenticationToken(authentication.getUserAuthentication(), "", authentication.getAuthorities());
  78. user = authenticationManager.authenticate(user);
  79. Object details = authentication.getDetails();
  80. authentication = new OAuth2Authentication(authentication.getOAuth2Request(), user);
  81. authentication.setDetails(details);*/
  82. // OAuth2Authentication 中的 Authentication userAuthentication 丢失了 Detail的信息,需要补上
  83. // 1.从tokenRequest中获取请求的信息,并重新构造成 UsernamePasswordAuthenticationToken
  84. // 2.设置好了Detail的信息再传入构造 PreAuthenticatedAuthenticationToken 交由后面的验证
  85. //tokenRequest.getRequestParameters();
  86. Object details = tokenRequest.getRequestParameters();
  87. UsernamePasswordAuthenticationToken userAuthentication = (UsernamePasswordAuthenticationToken) authentication.getUserAuthentication();
  88. userAuthentication.setDetails(details);
  89. // 去掉原来的,使用自己重新构造的 userAuthentication
  90. // Authentication user = new PreAuthenticatedAuthenticationToken(authentication.getUserAuthentication(), "", authentication.getAuthorities());
  91. Authentication user = new PreAuthenticatedAuthenticationToken(userAuthentication, "", authentication.getAuthorities());
  92. user = this.authenticationManager.authenticate(user);
  93. authentication = new OAuth2Authentication(authentication.getOAuth2Request(), user);
  94. authentication.setDetails(details);
  95. }
  96. String clientId = authentication.getOAuth2Request().getClientId();
  97. if (clientId == null || !clientId.equals(tokenRequest.getClientId())) {
  98. throw new InvalidGrantException("Wrong client for this refresh token: " + refreshTokenValue);
  99. }
  100. // clear out any access tokens already associated with the refresh
  101. // token.
  102. tokenStore.removeAccessTokenUsingRefreshToken(refreshToken);
  103. if (isExpired(refreshToken)) {
  104. tokenStore.removeRefreshToken(refreshToken);
  105. throw new InvalidTokenException("Invalid refresh token (expired): " + refreshToken);
  106. }
  107. authentication = createRefreshedAuthentication(authentication, tokenRequest);
  108. if (!reuseRefreshToken) {
  109. tokenStore.removeRefreshToken(refreshToken);
  110. refreshToken = createRefreshToken(authentication);
  111. }
  112. OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
  113. tokenStore.storeAccessToken(accessToken, authentication);
  114. if (!reuseRefreshToken) {
  115. tokenStore.storeRefreshToken(accessToken.getRefreshToken(), authentication);
  116. }
  117. return accessToken;
  118. }
  119. public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
  120. return tokenStore.getAccessToken(authentication);
  121. }
  122. /**
  123. * Create a refreshed authentication.
  124. *
  125. * @param authentication The authentication.
  126. * @param request The scope for the refreshed token.
  127. * @return The refreshed authentication.
  128. * @throws InvalidScopeException If the scope requested is invalid or wider than the original scope.
  129. */
  130. private OAuth2Authentication createRefreshedAuthentication(OAuth2Authentication authentication, TokenRequest request) {
  131. OAuth2Authentication narrowed = authentication;
  132. Set<String> scope = request.getScope();
  133. OAuth2Request clientAuth = authentication.getOAuth2Request().refresh(request);
  134. if (scope != null && !scope.isEmpty()) {
  135. Set<String> originalScope = clientAuth.getScope();
  136. if (originalScope == null || !originalScope.containsAll(scope)) {
  137. throw new InvalidScopeException("Unable to narrow the scope of the client authentication to " + scope
  138. + ".", originalScope);
  139. }
  140. else {
  141. clientAuth = clientAuth.narrowScope(scope);
  142. }
  143. }
  144. narrowed = new OAuth2Authentication(clientAuth, authentication.getUserAuthentication());
  145. return narrowed;
  146. }
  147. protected boolean isExpired(OAuth2RefreshToken refreshToken) {
  148. if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
  149. ExpiringOAuth2RefreshToken expiringToken = (ExpiringOAuth2RefreshToken) refreshToken;
  150. return expiringToken.getExpiration() == null
  151. || System.currentTimeMillis() > expiringToken.getExpiration().getTime();
  152. }
  153. return false;
  154. }
  155. public OAuth2AccessToken readAccessToken(String accessToken) {
  156. return tokenStore.readAccessToken(accessToken);
  157. }
  158. public OAuth2Authentication loadAuthentication(String accessTokenValue) throws AuthenticationException,
  159. InvalidTokenException {
  160. OAuth2AccessToken accessToken = tokenStore.readAccessToken(accessTokenValue);
  161. if (accessToken == null) {
  162. throw new InvalidTokenException("Invalid access token: " + accessTokenValue);
  163. }
  164. else if (accessToken.isExpired()) {
  165. tokenStore.removeAccessToken(accessToken);
  166. throw new InvalidTokenException("Access token expired: " + accessTokenValue);
  167. }
  168. OAuth2Authentication result = tokenStore.readAuthentication(accessToken);
  169. if (result == null) {
  170. // in case of race condition
  171. throw new InvalidTokenException("Invalid access token: " + accessTokenValue);
  172. }
  173. if (clientDetailsService != null) {
  174. String clientId = result.getOAuth2Request().getClientId();
  175. try {
  176. clientDetailsService.loadClientByClientId(clientId);
  177. }
  178. catch (ClientRegistrationException e) {
  179. throw new InvalidTokenException("Client not valid: " + clientId, e);
  180. }
  181. }
  182. return result;
  183. }
  184. public String getClientId(String tokenValue) {
  185. OAuth2Authentication authentication = tokenStore.readAuthentication(tokenValue);
  186. if (authentication == null) {
  187. throw new InvalidTokenException("Invalid access token: " + tokenValue);
  188. }
  189. OAuth2Request clientAuth = authentication.getOAuth2Request();
  190. if (clientAuth == null) {
  191. throw new InvalidTokenException("Invalid access token (no client id): " + tokenValue);
  192. }
  193. return clientAuth.getClientId();
  194. }
  195. public boolean revokeToken(String tokenValue) {
  196. OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
  197. if (accessToken == null) {
  198. return false;
  199. }
  200. if (accessToken.getRefreshToken() != null) {
  201. tokenStore.removeRefreshToken(accessToken.getRefreshToken());
  202. }
  203. tokenStore.removeAccessToken(accessToken);
  204. return true;
  205. }
  206. private OAuth2RefreshToken createRefreshToken(OAuth2Authentication authentication) {
  207. if (!isSupportRefreshToken(authentication.getOAuth2Request())) {
  208. return null;
  209. }
  210. int validitySeconds = getRefreshTokenValiditySeconds(authentication.getOAuth2Request());
  211. String value = UUID.randomUUID().toString();
  212. if (validitySeconds > 0) {
  213. return new DefaultExpiringOAuth2RefreshToken(value, new Date(System.currentTimeMillis()
  214. + (validitySeconds * 1000L)));
  215. }
  216. return new DefaultOAuth2RefreshToken(value);
  217. }
  218. private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) {
  219. DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(UUID.randomUUID().toString());
  220. int validitySeconds = getAccessTokenValiditySeconds(authentication.getOAuth2Request());
  221. if (validitySeconds > 0) {
  222. token.setExpiration(new Date(System.currentTimeMillis() + (validitySeconds * 1000L)));
  223. }
  224. token.setRefreshToken(refreshToken);
  225. token.setScope(authentication.getOAuth2Request().getScope());
  226. return accessTokenEnhancer != null ? accessTokenEnhancer.enhance(token, authentication) : token;
  227. }
  228. /**
  229. * The access token validity period in seconds
  230. *
  231. * @param clientAuth the current authorization request
  232. * @return the access token validity period in seconds
  233. */
  234. protected int getAccessTokenValiditySeconds(OAuth2Request clientAuth) {
  235. if (clientDetailsService != null) {
  236. ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
  237. Integer validity = client.getAccessTokenValiditySeconds();
  238. if (validity != null) {
  239. return validity;
  240. }
  241. }
  242. return accessTokenValiditySeconds;
  243. }
  244. /**
  245. * The refresh token validity period in seconds
  246. *
  247. * @param clientAuth the current authorization request
  248. * @return the refresh token validity period in seconds
  249. */
  250. protected int getRefreshTokenValiditySeconds(OAuth2Request clientAuth) {
  251. if (clientDetailsService != null) {
  252. ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
  253. Integer validity = client.getRefreshTokenValiditySeconds();
  254. if (validity != null) {
  255. return validity;
  256. }
  257. }
  258. return refreshTokenValiditySeconds;
  259. }
  260. /**
  261. * Is a refresh token supported for this client (or the global setting if
  262. * {@link #setClientDetailsService(ClientDetailsService) clientDetailsService} is not set.
  263. *
  264. * @param clientAuth the current authorization request
  265. * @return boolean to indicate if refresh token is supported
  266. */
  267. protected boolean isSupportRefreshToken(OAuth2Request clientAuth) {
  268. if (clientDetailsService != null) {
  269. ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
  270. return client.getAuthorizedGrantTypes().contains("refresh_token");
  271. }
  272. return this.supportRefreshToken;
  273. }
  274. /**
  275. * An access token enhancer that will be applied to a new token before it is saved in the token store.
  276. *
  277. * @param accessTokenEnhancer the access token enhancer to set
  278. */
  279. public void setTokenEnhancer(TokenEnhancer accessTokenEnhancer) {
  280. this.accessTokenEnhancer = accessTokenEnhancer;
  281. }
  282. /**
  283. * The validity (in seconds) of the refresh token. If less than or equal to zero then the tokens will be
  284. * non-expiring.
  285. *
  286. * @param refreshTokenValiditySeconds The validity (in seconds) of the refresh token.
  287. */
  288. public void setRefreshTokenValiditySeconds(int refreshTokenValiditySeconds) {
  289. this.refreshTokenValiditySeconds = refreshTokenValiditySeconds;
  290. }
  291. /**
  292. * The default validity (in seconds) of the access token. Zero or negative for non-expiring tokens. If a client
  293. * details service is set the validity period will be read from the client, defaulting to this value if not defined
  294. * by the client.
  295. *
  296. * @param accessTokenValiditySeconds The validity (in seconds) of the access token.
  297. */
  298. public void setAccessTokenValiditySeconds(int accessTokenValiditySeconds) {
  299. this.accessTokenValiditySeconds = accessTokenValiditySeconds;
  300. }
  301. /**
  302. * Whether to support the refresh token.
  303. *
  304. * @param supportRefreshToken Whether to support the refresh token.
  305. */
  306. public void setSupportRefreshToken(boolean supportRefreshToken) {
  307. this.supportRefreshToken = supportRefreshToken;
  308. }
  309. /**
  310. * Whether to reuse refresh tokens (until expired).
  311. *
  312. * @param reuseRefreshToken Whether to reuse refresh tokens (until expired).
  313. */
  314. public void setReuseRefreshToken(boolean reuseRefreshToken) {
  315. this.reuseRefreshToken = reuseRefreshToken;
  316. }
  317. /**
  318. * The persistence strategy for token storage.
  319. *
  320. * @param tokenStore the store for access and refresh tokens.
  321. */
  322. public void setTokenStore(TokenStore tokenStore) {
  323. this.tokenStore = tokenStore;
  324. }
  325. /**
  326. * An authentication manager that will be used (if provided) to check the user authentication when a token is
  327. * refreshed.
  328. *
  329. * @param authenticationManager the authenticationManager to set
  330. */
  331. public void setAuthenticationManager(AuthenticationManager authenticationManager) {
  332. this.authenticationManager = authenticationManager;
  333. }
  334. /**
  335. * The client details service to use for looking up clients (if necessary). Optional if the access token expiry is
  336. * set globally via {@link #setAccessTokenValiditySeconds(int)}.
  337. *
  338. * @param clientDetailsService the client details service
  339. */
  340. public void setClientDetailsService(ClientDetailsService clientDetailsService) {
  341. this.clientDetailsService = clientDetailsService;
  342. }
  343. }
  1. 到认证服务器配置类 AuthorizationServerConfig 配置刚刚自定义的两个类 CustomUserDetailsByNameServiceWrapper 和 CustomTokenServices

  1. @Override
  2. public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  3. endpoints.tokenStore(jwtTokenStore()) // 根据自己需要
  4. .tokenEnhancer(jwtAccessTokenConverter())
  5. .reuseRefreshTokens(true)
  6. .authenticationManager(authenticationManager)
  7. .userDetailsService(userDetailsService)
  8. .tokenServices(customTokenServices(endpoints)); // 自定义TokenServices
  9. }
  10. public CustomTokenServices customTokenServices(AuthorizationServerEndpointsConfigurer endpoints){
  11. CustomTokenServices tokenServices = new CustomTokenServices();
  12. tokenServices.setTokenStore(endpoints.getTokenStore());
  13. tokenServices.setSupportRefreshToken(true);
  14. tokenServices.setReuseRefreshToken(true);
  15. tokenServices.setClientDetailsService(clientDetails());
  16. tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
  17. // 设置自定义的CustomUserDetailsByNameServiceWrapper
  18. if (userDetailsService != null) {
  19. PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
  20. provider.setPreAuthenticatedUserDetailsService(new CustomUserDetailsByNameServiceWrapper(userDetailsService));
  21. tokenServices.setAuthenticationManager(new ProviderManager(Arrays.asList(provider)));
  22. }
  23. return tokenServices;
  24. }
  1. 至此,可以刷新token试试了。

在获取Token的时候,像client_id,client_secret等默认的请求参数,框架会自动放到details中,但是在刷新token的时候不知什么原因,details中并没有放入请求的参数,所以需要自己重新构造,还好这些信息都保存在tokenRequest中,所以new一个UsernamePasswordAuthenticationToken,把它们都放进details中,再传入 PreAuthenticatedAuthenticationToken,后续就交由框架去验证就可以了 。这一步操作就是CustomTokenServices类refreshAccessToken方法

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/481608
推荐阅读
相关标签
  

闽ICP备14008679号