当前位置:   article > 正文

spring security webflux 三方用户授权登录说明_webflux响应式 oauth授权登录

webflux响应式 oauth授权登录

spring security webflux 三方用户授权说明

 

spring security 默认整合了github、google、facebook、okta三方登录功能,直接配置client-id、client-secret等参数就可自动登录;

其他三方授权方(如gitee、微博等)需要实现相关的接口

 

 

*************************

相关类及接口

 

CommonOAuth2Provider:默认集成的三方授权提供方

  1. public enum CommonOAuth2Provider {
  2. GOOGLE {
  3. public Builder getBuilder(String registrationId) {
  4. Builder builder = this.getBuilder(registrationId, ClientAuthenticationMethod.BASIC, "{baseUrl}/{action}/oauth2/code/{registrationId}");
  5. builder.scope(new String[]{"openid", "profile", "email"});
  6. builder.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth");
  7. builder.tokenUri("https://www.googleapis.com/oauth2/v4/token");
  8. builder.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs");
  9. builder.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo");
  10. builder.userNameAttributeName("sub");
  11. builder.clientName("Google");
  12. return builder;
  13. }
  14. },
  15. GITHUB {
  16. public Builder getBuilder(String registrationId) {
  17. Builder builder = this.getBuilder(registrationId, ClientAuthenticationMethod.BASIC, "{baseUrl}/{action}/oauth2/code/{registrationId}");
  18. builder.scope(new String[]{"read:user"});
  19. builder.authorizationUri("https://github.com/login/oauth/authorize");
  20. builder.tokenUri("https://github.com/login/oauth/access_token");
  21. builder.userInfoUri("https://api.github.com/user");
  22. builder.userNameAttributeName("id");
  23. builder.clientName("GitHub");
  24. return builder;
  25. }
  26. },
  27. FACEBOOK {
  28. public Builder getBuilder(String registrationId) {
  29. Builder builder = this.getBuilder(registrationId, ClientAuthenticationMethod.POST, "{baseUrl}/{action}/oauth2/code/{registrationId}");
  30. builder.scope(new String[]{"public_profile", "email"});
  31. builder.authorizationUri("https://www.facebook.com/v2.8/dialog/oauth");
  32. builder.tokenUri("https://graph.facebook.com/v2.8/oauth/access_token");
  33. builder.userInfoUri("https://graph.facebook.com/me?fields=id,name,email");
  34. builder.userNameAttributeName("id");
  35. builder.clientName("Facebook");
  36. return builder;
  37. }
  38. },
  39. OKTA {
  40. public Builder getBuilder(String registrationId) {
  41. Builder builder = this.getBuilder(registrationId, ClientAuthenticationMethod.BASIC, "{baseUrl}/{action}/oauth2/code/{registrationId}");
  42. builder.scope(new String[]{"openid", "profile", "email"});
  43. builder.userNameAttributeName("sub");
  44. builder.clientName("Okta");
  45. return builder;
  46. }
  47. };
  48. private static final String DEFAULT_REDIRECT_URL = "{baseUrl}/{action}/oauth2/code/{registrationId}";
  49. private CommonOAuth2Provider() {
  50. }
  51. protected final Builder getBuilder(String registrationId, ClientAuthenticationMethod method, String redirectUri) {
  52. Builder builder = ClientRegistration.withRegistrationId(registrationId);
  53. builder.clientAuthenticationMethod(method);
  54. builder.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE);
  55. builder.redirectUriTemplate(redirectUri);
  56. return builder;
  57. }
  58. public abstract Builder getBuilder(String var1);
  59. }

 

 

ServerHttpSecurity:oauth2配置入口类

  1. public class ServerHttpSecurity {
  2. ******************
  3. 内部类:ServerHttpSecurity.OAuth2LoginSpec
  4. public class OAuth2LoginSpec {
  5. private ReactiveClientRegistrationRepository clientRegistrationRepository; //存储授权提供方
  6. private ServerOAuth2AuthorizedClientRepository authorizedClientRepository; //存储授权客户端
  7. private ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository; //授权请求操作
  8. private ReactiveAuthenticationManager authenticationManager; //获取access_token,成功后加载OAuth2User
  9. private ServerSecurityContextRepository securityContextRepository;
  10. private ServerAuthenticationConverter authenticationConverter;
  11. private ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver;
  12. private ServerWebExchangeMatcher authenticationMatcher;
  13. private ServerAuthenticationSuccessHandler authenticationSuccessHandler;
  14. private ServerAuthenticationFailureHandler authenticationFailureHandler;
  15. public ServerHttpSecurity.OAuth2LoginSpec authenticationManager(ReactiveAuthenticationManager authenticationManager) {
  16. public ServerHttpSecurity.OAuth2LoginSpec securityContextRepository(ServerSecurityContextRepository securityContextRepository) {
  17. public ServerHttpSecurity.OAuth2LoginSpec authenticationSuccessHandler(ServerAuthenticationSuccessHandler authenticationSuccessHandler) {
  18. public ServerHttpSecurity.OAuth2LoginSpec authenticationFailureHandler(ServerAuthenticationFailureHandler authenticationFailureHandler) {
  19. private ReactiveAuthenticationManager getAuthenticationManager() {
  20. if (this.authenticationManager == null) {
  21. this.authenticationManager = this.createDefault();
  22. }//如果没有设置authenticationManager,则创建默认的authenticationManager
  23. return this.authenticationManager;
  24. }
  25. private ReactiveAuthenticationManager createDefault() {
  26. ReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> client = this.getAccessTokenResponseClient();
  27. //获取access_token客户端,如果不存在则创建WebClientReactiveAuthorizationCodeTokenResponseClient
  28. ReactiveAuthenticationManager result = new OAuth2LoginReactiveAuthenticationManager(client, this.getOauth2UserService());
  29. //创建OAuth2LoginReactiveAuthenticationManager,该对象可同时获取access_token、oauth2User(如果不存在,默认为DefaultReactiveOAuth2UserService对象)
  30. boolean oidcAuthenticationProviderEnabled = ClassUtils.isPresent("org.springframework.security.oauth2.jwt.JwtDecoder", this.getClass().getClassLoader());
  31. if (oidcAuthenticationProviderEnabled) {
  32. OidcAuthorizationCodeReactiveAuthenticationManager oidc = new OidcAuthorizationCodeReactiveAuthenticationManager(client, this.getOidcUserService());
  33. ResolvableType type = ResolvableType.forClassWithGenerics(ReactiveJwtDecoderFactory.class, new Class[]{ClientRegistration.class});
  34. ReactiveJwtDecoderFactory<ClientRegistration> jwtDecoderFactory = (ReactiveJwtDecoderFactory)ServerHttpSecurity.this.getBeanOrNull(type);
  35. if (jwtDecoderFactory != null) {
  36. oidc.setJwtDecoderFactory(jwtDecoderFactory);
  37. }
  38. result = new DelegatingReactiveAuthenticationManager(new ReactiveAuthenticationManager[]{oidc, (ReactiveAuthenticationManager)result});
  39. }
  40. return (ReactiveAuthenticationManager)result;
  41. }
  42. public ServerHttpSecurity.OAuth2LoginSpec authenticationConverter(ServerAuthenticationConverter authenticationConverter) {
  43. this.authenticationConverter = authenticationConverter;
  44. return this;
  45. }
  46. private ServerAuthenticationConverter getAuthenticationConverter(ReactiveClientRegistrationRepository clientRegistrationRepository) {
  47. if (this.authenticationConverter == null) {
  48. ServerOAuth2AuthorizationCodeAuthenticationTokenConverter authenticationConverter = new ServerOAuth2AuthorizationCodeAuthenticationTokenConverter(clientRegistrationRepository);
  49. authenticationConverter.setAuthorizationRequestRepository(this.getAuthorizationRequestRepository());
  50. this.authenticationConverter = authenticationConverter;
  51. }
  52. return this.authenticationConverter;
  53. }
  54. public ServerHttpSecurity.OAuth2LoginSpec clientRegistrationRepository(ReactiveClientRegistrationRepository clientRegistrationRepository) {
  55. this.clientRegistrationRepository = clientRegistrationRepository;
  56. return this;
  57. }
  58. public ServerHttpSecurity.OAuth2LoginSpec authorizedClientService(ReactiveOAuth2AuthorizedClientService authorizedClientService) {
  59. this.authorizedClientRepository = new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(authorizedClientService);
  60. return this;
  61. }
  62. public ServerHttpSecurity.OAuth2LoginSpec authorizedClientRepository(ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {
  63. public ServerHttpSecurity.OAuth2LoginSpec authorizationRequestRepository(ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository) {
  64. public ServerHttpSecurity.OAuth2LoginSpec authorizationRequestResolver(ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver) {
  65. public ServerHttpSecurity.OAuth2LoginSpec authenticationMatcher(ServerWebExchangeMatcher authenticationMatcher) {
  66. private ServerWebExchangeMatcher getAuthenticationMatcher() {
  67. if (this.authenticationMatcher == null) {
  68. this.authenticationMatcher = this.createAttemptAuthenticationRequestMatcher();
  69. } //如果没有设置authenticationManager,则创建默认的authenticationManager
  70. return this.authenticationMatcher;
  71. }
  72. public ServerHttpSecurity and() {
  73. return ServerHttpSecurity.this;
  74. }
  75. protected void configure(ServerHttpSecurity http) {
  76. ReactiveClientRegistrationRepository clientRegistrationRepository = this.getClientRegistrationRepository(); //获取clientRegistration
  77. ServerOAuth2AuthorizedClientRepository authorizedClientRepository = this.getAuthorizedClientRepository(); //获取authorizedClient
  78. OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter = this.getRedirectWebFilter(); //认证请求跳转过滤器,获取授权码
  79. ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository = this.getAuthorizationRequestRepository();
  80. oauthRedirectFilter.setAuthorizationRequestRepository(authorizationRequestRepository);
  81. oauthRedirectFilter.setRequestCache(http.requestCache.requestCache);
  82. ReactiveAuthenticationManager manager = this.getAuthenticationManager(); //获取access_token、oauth2User
  83. AuthenticationWebFilter authenticationFilter = new OAuth2LoginAuthenticationWebFilter(manager, authorizedClientRepository);
  84. authenticationFilter.setRequiresAuthenticationMatcher(this.getAuthenticationMatcher());
  85. authenticationFilter.setServerAuthenticationConverter(this.getAuthenticationConverter(clientRegistrationRepository));
  86. authenticationFilter.setAuthenticationSuccessHandler(this.getAuthenticationSuccessHandler(http));
  87. authenticationFilter.setAuthenticationFailureHandler(this.getAuthenticationFailureHandler());
  88. authenticationFilter.setSecurityContextRepository(this.securityContextRepository);
  89. this.setDefaultEntryPoints(http);
  90. http.addFilterAt(oauthRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC);
  91. http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION);
  92. }
  93. private void setDefaultEntryPoints(ServerHttpSecurity http) {
  94. String defaultLoginPage = "/login";
  95. Map<String, String> urlToText = http.oauth2Login.getLinks();
  96. String providerLoginPage = null;
  97. if (urlToText.size() == 1) {
  98. providerLoginPage = (String)urlToText.keySet().iterator().next();
  99. }
  100. MediaTypeServerWebExchangeMatcher htmlMatcher = new MediaTypeServerWebExchangeMatcher(new MediaType[]{MediaType.APPLICATION_XHTML_XML, new MediaType("image", "*"), MediaType.TEXT_HTML, MediaType.TEXT_PLAIN});
  101. htmlMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
  102. ServerWebExchangeMatcher xhrMatcher = (exchange) -> {
  103. return exchange.getRequest().getHeaders().getOrEmpty("X-Requested-With").contains("XMLHttpRequest") ? MatchResult.match() : MatchResult.notMatch();
  104. };
  105. ServerWebExchangeMatcher notXhrMatcher = new NegatedServerWebExchangeMatcher(xhrMatcher);
  106. ServerWebExchangeMatcher defaultEntryPointMatcher = new AndServerWebExchangeMatcher(new ServerWebExchangeMatcher[]{notXhrMatcher, htmlMatcher});
  107. if (providerLoginPage != null) {
  108. ServerWebExchangeMatcher loginPageMatcher = new PathPatternParserServerWebExchangeMatcher(defaultLoginPage);
  109. ServerWebExchangeMatcher faviconMatcher = new PathPatternParserServerWebExchangeMatcher("/favicon.ico");
  110. ServerWebExchangeMatcher defaultLoginPageMatcher = new AndServerWebExchangeMatcher(new ServerWebExchangeMatcher[]{new OrServerWebExchangeMatcher(new ServerWebExchangeMatcher[]{loginPageMatcher, faviconMatcher}), defaultEntryPointMatcher});
  111. ServerWebExchangeMatcher matcher = new AndServerWebExchangeMatcher(new ServerWebExchangeMatcher[]{notXhrMatcher, new NegatedServerWebExchangeMatcher(defaultLoginPageMatcher)});
  112. RedirectServerAuthenticationEntryPoint entryPoint = new RedirectServerAuthenticationEntryPoint(providerLoginPage);
  113. entryPoint.setRequestCache(http.requestCache.requestCache);
  114. http.defaultEntryPoints.add(new DelegateEntry(matcher, entryPoint));
  115. }
  116. RedirectServerAuthenticationEntryPoint defaultEntryPoint = new RedirectServerAuthenticationEntryPoint(defaultLoginPage);
  117. defaultEntryPoint.setRequestCache(http.requestCache.requestCache);
  118. http.defaultEntryPoints.add(new DelegateEntry(defaultEntryPointMatcher, defaultEntryPoint));
  119. }
  120. private ServerAuthenticationSuccessHandler getAuthenticationSuccessHandler(ServerHttpSecurity http) {
  121. if (this.authenticationSuccessHandler == null) {
  122. RedirectServerAuthenticationSuccessHandler handler = new RedirectServerAuthenticationSuccessHandler();
  123. handler.setRequestCache(http.requestCache.requestCache);
  124. this.authenticationSuccessHandler = handler;
  125. }
  126. return this.authenticationSuccessHandler;
  127. }
  128. private ServerAuthenticationFailureHandler getAuthenticationFailureHandler() {
  129. if (this.authenticationFailureHandler == null) {
  130. this.authenticationFailureHandler = new RedirectServerAuthenticationFailureHandler("/login?error");
  131. }
  132. return this.authenticationFailureHandler;
  133. }
  134. private ServerWebExchangeMatcher createAttemptAuthenticationRequestMatcher() {
  135. return new PathPatternParserServerWebExchangeMatcher("/login/oauth2/code/{registrationId}");
  136. }
  137. private ReactiveOAuth2UserService<OidcUserRequest, OidcUser> getOidcUserService() {
  138. ResolvableType type = ResolvableType.forClassWithGenerics(ReactiveOAuth2UserService.class, new Class[]{OidcUserRequest.class, OidcUser.class});
  139. ReactiveOAuth2UserService<OidcUserRequest, OidcUser> bean = (ReactiveOAuth2UserService)ServerHttpSecurity.this.getBeanOrNull(type);
  140. return (ReactiveOAuth2UserService)(bean == null ? new OidcReactiveOAuth2UserService() : bean);
  141. }
  142. private ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> getOauth2UserService() {
  143. //获取认证用户操作类
  144. ResolvableType type = ResolvableType.forClassWithGenerics(ReactiveOAuth2UserService.class, new Class[]{OAuth2UserRequest.class, OAuth2User.class});
  145. ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> bean = (ReactiveOAuth2UserService)ServerHttpSecurity.this.getBeanOrNull(type);
  146. return (ReactiveOAuth2UserService)(bean == null ? new DefaultReactiveOAuth2UserService() : bean);
  147. }
  148. private Map<String, String> getLinks() {
  149. Iterable<ClientRegistration> registrations = (Iterable)ServerHttpSecurity.this.getBeanOrNull(ResolvableType.forClassWithGenerics(Iterable.class, new Class[]{ClientRegistration.class}));
  150. if (registrations == null) {
  151. return Collections.emptyMap();
  152. } else {
  153. Map<String, String> result = new HashMap();
  154. registrations.iterator().forEachRemaining((r) -> {
  155. String var10000 = (String)result.put("/oauth2/authorization/" + r.getRegistrationId(), r.getClientName());
  156. });
  157. return result;
  158. }
  159. }
  160. private ReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> getAccessTokenResponseClient() {
  161. ResolvableType type = ResolvableType.forClassWithGenerics(ReactiveOAuth2AccessTokenResponseClient.class, new Class[]{OAuth2AuthorizationCodeGrantRequest.class});
  162. ReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> bean = (ReactiveOAuth2AccessTokenResponseClient)ServerHttpSecurity.this.getBeanOrNull(type);
  163. return (ReactiveOAuth2AccessTokenResponseClient)(bean == null ? new WebClientReactiveAuthorizationCodeTokenResponseClient() : bean);
  164. }
  165. private ReactiveClientRegistrationRepository getClientRegistrationRepository() {
  166. if (this.clientRegistrationRepository == null) {
  167. this.clientRegistrationRepository = (ReactiveClientRegistrationRepository)ServerHttpSecurity.this.getBeanOrNull(ReactiveClientRegistrationRepository.class);
  168. }
  169. return this.clientRegistrationRepository;
  170. }
  171. private OAuth2AuthorizationRequestRedirectWebFilter getRedirectWebFilter() {
  172. OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter;
  173. if (this.authorizationRequestResolver == null) {
  174. oauthRedirectFilter = new OAuth2AuthorizationRequestRedirectWebFilter(this.getClientRegistrationRepository());
  175. } else {
  176. oauthRedirectFilter = new OAuth2AuthorizationRequestRedirectWebFilter(this.authorizationRequestResolver);
  177. }
  178. return oauthRedirectFilter;
  179. }
  180. private ServerOAuth2AuthorizedClientRepository getAuthorizedClientRepository() {
  181. ServerOAuth2AuthorizedClientRepository result = this.authorizedClientRepository;
  182. if (result == null) {
  183. result = (ServerOAuth2AuthorizedClientRepository)ServerHttpSecurity.this.getBeanOrNull(ServerOAuth2AuthorizedClientRepository.class);
  184. }
  185. if (result == null) {
  186. ReactiveOAuth2AuthorizedClientService authorizedClientService = this.getAuthorizedClientService();
  187. if (authorizedClientService != null) {
  188. result = new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(authorizedClientService);
  189. }
  190. }
  191. return (ServerOAuth2AuthorizedClientRepository)result;
  192. }
  193. private ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> getAuthorizationRequestRepository() {
  194. if (this.authorizationRequestRepository == null) {
  195. this.authorizationRequestRepository = new WebSessionOAuth2ServerAuthorizationRequestRepository();
  196. }
  197. return this.authorizationRequestRepository;
  198. }
  199. private ReactiveOAuth2AuthorizedClientService getAuthorizedClientService() {
  200. ReactiveOAuth2AuthorizedClientService service = (ReactiveOAuth2AuthorizedClientService)ServerHttpSecurity.this.getBeanOrNull(ReactiveOAuth2AuthorizedClientService.class);
  201. if (service == null) {
  202. service = new InMemoryReactiveOAuth2AuthorizedClientService(this.getClientRegistrationRepository());
  203. }
  204. return (ReactiveOAuth2AuthorizedClientService)service;
  205. }
  206. private OAuth2LoginSpec() {
  207. }
  208. }

 

 

*****************

ReactiveClientRegistrationRepository

 

ReactiveClientRegistrationRepository:存储授权提供方

  1. public interface ReactiveClientRegistrationRepository {
  2. Mono<ClientRegistration> findByRegistrationId(String var1);
  3. }

 

InMemoryReactiveClientRegistrationRepository:内存中存储clientRegistration

  1. public final class InMemoryReactiveClientRegistrationRepository implements ReactiveClientRegistrationRepository, Iterable<ClientRegistration> {
  2. private final Map<String, ClientRegistration> clientIdToClientRegistration;
  3. public InMemoryReactiveClientRegistrationRepository(ClientRegistration... registrations) {
  4. this(toList(registrations));
  5. }
  6. private static List<ClientRegistration> toList(ClientRegistration... registrations) {
  7. Assert.notEmpty(registrations, "registrations cannot be null or empty");
  8. return Arrays.asList(registrations);
  9. }
  10. public InMemoryReactiveClientRegistrationRepository(List<ClientRegistration> registrations) {
  11. this.clientIdToClientRegistration = toUnmodifiableConcurrentMap(registrations);
  12. }
  13. public Mono<ClientRegistration> findByRegistrationId(String registrationId) {
  14. return Mono.justOrEmpty(this.clientIdToClientRegistration.get(registrationId));
  15. }
  16. public Iterator<ClientRegistration> iterator() {
  17. return this.clientIdToClientRegistration.values().iterator();
  18. }
  19. private static Map<String, ClientRegistration> toUnmodifiableConcurrentMap(List<ClientRegistration> registrations) {
  20. Assert.notEmpty(registrations, "registrations cannot be null or empty");
  21. ConcurrentHashMap<String, ClientRegistration> result = new ConcurrentHashMap();
  22. Iterator var2 = registrations.iterator();
  23. while(var2.hasNext()) {
  24. ClientRegistration registration = (ClientRegistration)var2.next();
  25. Assert.notNull(registration, "no registration can be null");
  26. if (result.containsKey(registration.getRegistrationId())) {
  27. throw new IllegalStateException(String.format("Duplicate key %s", registration.getRegistrationId()));
  28. }
  29. result.put(registration.getRegistrationId(), registration);
  30. }
  31. return Collections.unmodifiableMap(result);
  32. }
  33. }

 

clientRegistration:clientRegistration属性

  1. public final class ClientRegistration implements Serializable {
  2. private static final long serialVersionUID = 530L;
  3. private String registrationId;
  4. private String clientId;
  5. private String clientSecret;
  6. private ClientAuthenticationMethod clientAuthenticationMethod;
  7. private AuthorizationGrantType authorizationGrantType;
  8. private String redirectUriTemplate;
  9. private Set<String> scopes;
  10. private ClientRegistration.ProviderDetails providerDetails;
  11. private String clientName;
  12. ***********
  13. 内部类:ClientRegistration.ProviderDetails
  14. public class ProviderDetails implements Serializable {
  15. private static final long serialVersionUID = 530L;
  16. private String authorizationUri;
  17. private String tokenUri;
  18. private ClientRegistration.ProviderDetails.UserInfoEndpoint userInfoEndpoint;
  19. private String jwkSetUri;
  20. private Map<String, Object> configurationMetadata;

 

 

*****************

authenticationManager

 

ReactiveAuthenticationManager:认证authentication接口

  1. @FunctionalInterface
  2. public interface ReactiveAuthenticationManager {
  3. Mono<Authentication> authenticate(Authentication var1);
  4. }

 

OAuth2LoginReactiveAuthenticationManager:认证autentication,认证成功后加载认证用户

  1. public class OAuth2LoginReactiveAuthenticationManager implements ReactiveAuthenticationManager {
  2. private final ReactiveAuthenticationManager authorizationCodeManager;
  3. private final ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> userService;
  4. private GrantedAuthoritiesMapper authoritiesMapper = (authorities) -> {
  5. return authorities;
  6. };
  7. public OAuth2LoginReactiveAuthenticationManager(ReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient, ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> userService) {
  8. Assert.notNull(accessTokenResponseClient, "accessTokenResponseClient cannot be null");
  9. Assert.notNull(userService, "userService cannot be null");
  10. this.authorizationCodeManager = new OAuth2AuthorizationCodeReactiveAuthenticationManager(accessTokenResponseClient);
  11. this.userService = userService;
  12. }
  13. public Mono<Authentication> authenticate(Authentication authentication) {
  14. //认证authentication
  15. return Mono.defer(() -> {
  16. OAuth2AuthorizationCodeAuthenticationToken token = (OAuth2AuthorizationCodeAuthenticationToken)authentication;
  17. return token.getAuthorizationExchange().getAuthorizationRequest().getScopes().contains("openid") ? Mono.empty() : this.authorizationCodeManager.authenticate(token).onErrorMap(OAuth2AuthorizationException.class, (e) -> {
  18. return new OAuth2AuthenticationException(e.getError(), e.getError().toString());
  19. }).cast(OAuth2AuthorizationCodeAuthenticationToken.class).flatMap(this::onSuccess);
  20. });
  21. }
  22. private Mono<OAuth2LoginAuthenticationToken> onSuccess(OAuth2AuthorizationCodeAuthenticationToken authentication) {
  23. //认证成功后,加载认证用户
  24. OAuth2AccessToken accessToken = authentication.getAccessToken();
  25. Map<String, Object> additionalParameters = authentication.getAdditionalParameters();
  26. OAuth2UserRequest userRequest = new OAuth2UserRequest(authentication.getClientRegistration(), accessToken, additionalParameters);
  27. return this.userService.loadUser(userRequest).map((oauth2User) -> {
  28. Collection<? extends GrantedAuthority> mappedAuthorities = this.authoritiesMapper.mapAuthorities(oauth2User.getAuthorities());
  29. OAuth2LoginAuthenticationToken authenticationResult = new OAuth2LoginAuthenticationToken(authentication.getClientRegistration(), authentication.getAuthorizationExchange(), oauth2User, mappedAuthorities, accessToken, authentication.getRefreshToken());
  30. return authenticationResult;
  31. });
  32. }
  33. }

 

ReactiveOAuth2UserService:加载认证用户接口

  1. @FunctionalInterface
  2. public interface ReactiveOAuth2UserService<R extends OAuth2UserRequest, U extends OAuth2User> {
  3. Mono<U> loadUser(R var1) throws OAuth2AuthenticationException;
  4. }

 

DefaultReactiveOAuth2UserService:默认加载认证用户实现类

  1. public class DefaultReactiveOAuth2UserService implements ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> {
  2. private static final String INVALID_USER_INFO_RESPONSE_ERROR_CODE = "invalid_user_info_response";
  3. private static final String MISSING_USER_INFO_URI_ERROR_CODE = "missing_user_info_uri";
  4. private static final String MISSING_USER_NAME_ATTRIBUTE_ERROR_CODE = "missing_user_name_attribute";
  5. private WebClient webClient = WebClient.create();
  6. public DefaultReactiveOAuth2UserService() {
  7. }
  8. public Mono<OAuth2User> loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
  9. //加载认证用户
  10. return Mono.defer(() -> {
  11. Assert.notNull(userRequest, "userRequest cannot be null");
  12. String userInfoUri = userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri();
  13. if (!StringUtils.hasText(userInfoUri)) {
  14. OAuth2Error oauth2Error = new OAuth2Error("missing_user_info_uri", "Missing required UserInfo Uri in UserInfoEndpoint for Client Registration: " + userRequest.getClientRegistration().getRegistrationId(), (String)null);
  15. throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
  16. } else {
  17. String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName();
  18. if (!StringUtils.hasText(userNameAttributeName)) {
  19. OAuth2Error oauth2Errorx = new OAuth2Error("missing_user_name_attribute", "Missing required \"user name\" attribute name in UserInfoEndpoint for Client Registration: " + userRequest.getClientRegistration().getRegistrationId(), (String)null);
  20. throw new OAuth2AuthenticationException(oauth2Errorx, oauth2Errorx.toString());
  21. } else {
  22. ParameterizedTypeReference<Map<String, Object>> typeReference = new ParameterizedTypeReference<Map<String, Object>>() {
  23. };
  24. AuthenticationMethod authenticationMethod = userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getAuthenticationMethod();
  25. RequestHeadersSpec requestHeadersSpec;
  26. if (AuthenticationMethod.FORM.equals(authenticationMethod)) {
  27. requestHeadersSpec = ((RequestBodySpec)((RequestBodySpec)((RequestBodySpec)this.webClient.post().uri(userInfoUri, new Object[0])).header("Accept", new String[]{"application/json"})).header("Content-Type", new String[]{"application/x-www-form-urlencoded"})).syncBody("access_token=" + userRequest.getAccessToken().getTokenValue());
  28. } else {
  29. requestHeadersSpec = this.webClient.get().uri(userInfoUri, new Object[0]).header("Accept", new String[]{"application/json"}).headers((headers) -> {
  30. headers.setBearerAuth(userRequest.getAccessToken().getTokenValue());
  31. });
  32. }
  33. Mono<Map<String, Object>> userAttributes = requestHeadersSpec.retrieve().onStatus((s) -> {
  34. return s != HttpStatus.OK;
  35. }, (response) -> {
  36. return parse(response).map((userInfoErrorResponse) -> {
  37. String description = userInfoErrorResponse.getErrorObject().getDescription();
  38. OAuth2Error oauth2Error = new OAuth2Error("invalid_user_info_response", description, (String)null);
  39. throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
  40. });
  41. }).bodyToMono(typeReference);
  42. return userAttributes.map((attrs) -> {
  43. GrantedAuthority authority = new OAuth2UserAuthority(attrs);
  44. Set<GrantedAuthority> authorities = new HashSet();
  45. authorities.add(authority);
  46. OAuth2AccessToken token = userRequest.getAccessToken();
  47. Iterator var6 = token.getScopes().iterator();
  48. while(var6.hasNext()) {
  49. String scope = (String)var6.next();
  50. authorities.add(new SimpleGrantedAuthority("SCOPE_" + scope));
  51. }
  52. return new DefaultOAuth2User(authorities, attrs, userNameAttributeName);
  53. }).onErrorMap((e) -> {
  54. return e instanceof IOException;
  55. }, (t) -> {
  56. return new AuthenticationServiceException("Unable to access the userInfoEndpoint " + userInfoUri, t);
  57. }).onErrorMap((t) -> {
  58. return !(t instanceof AuthenticationServiceException);
  59. }, (t) -> {
  60. OAuth2Error oauth2Error = new OAuth2Error("invalid_user_info_response", "An error occurred reading the UserInfo Success response: " + t.getMessage(), (String)null);
  61. return new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), t);
  62. });
  63. }
  64. }
  65. });
  66. }
  67. public void setWebClient(WebClient webClient) {
  68. Assert.notNull(webClient, "webClient cannot be null");
  69. this.webClient = webClient;
  70. }
  71. private static Mono<UserInfoErrorResponse> parse(ClientResponse httpResponse) {
  72. String wwwAuth = httpResponse.headers().asHttpHeaders().getFirst("WWW-Authenticate");
  73. if (!StringUtils.isEmpty(wwwAuth)) {
  74. return Mono.fromCallable(() -> {
  75. return UserInfoErrorResponse.parse(wwwAuth);
  76. });
  77. } else {
  78. ParameterizedTypeReference<Map<String, String>> typeReference = new ParameterizedTypeReference<Map<String, String>>() {
  79. };
  80. return httpResponse.bodyToMono(typeReference).map((body) -> {
  81. return new UserInfoErrorResponse(ErrorObject.parse(new JSONObject(body)));
  82. });
  83. }
  84. }
  85. }

 

 

*****************

获取 access_token

 

WebClientReactiveAuthorizationCodeTokenResponseClient:获取access_token的客户端

  1. public class WebClientReactiveAuthorizationCodeTokenResponseClient extends AbstractWebClientReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> {
  2. public WebClientReactiveAuthorizationCodeTokenResponseClient() {
  3. }
  4. ClientRegistration clientRegistration(OAuth2AuthorizationCodeGrantRequest grantRequest) {
  5. return grantRequest.getClientRegistration();
  6. }
  7. Set<String> scopes(OAuth2AuthorizationCodeGrantRequest grantRequest) {
  8. return Collections.emptySet();
  9. }
  10. Set<String> defaultScopes(OAuth2AuthorizationCodeGrantRequest grantRequest) {
  11. return grantRequest.getAuthorizationExchange().getAuthorizationRequest().getScopes();
  12. }
  13. FormInserter<String> populateTokenRequestBody(OAuth2AuthorizationCodeGrantRequest grantRequest, FormInserter<String> body) {
  14. super.populateTokenRequestBody(grantRequest, body);
  15. OAuth2AuthorizationExchange authorizationExchange = grantRequest.getAuthorizationExchange();
  16. OAuth2AuthorizationResponse authorizationResponse = authorizationExchange.getAuthorizationResponse();
  17. body.with("code", authorizationResponse.getCode());
  18. String redirectUri = authorizationExchange.getAuthorizationRequest().getRedirectUri();
  19. if (redirectUri != null) {
  20. body.with("redirect_uri", redirectUri);
  21. }
  22. String codeVerifier = (String)authorizationExchange.getAuthorizationRequest().getAttribute("code_verifier");
  23. if (codeVerifier != null) {
  24. body.with("code_verifier", codeVerifier);
  25. }
  26. return body;
  27. }
  28. }

 

AbstractWebClientOAuth2ReactiveAccessTokenResponseClient:使用webClient获取acccess_token

  1. abstract class AbstractWebClientReactiveOAuth2AccessTokenResponseClient<T extends AbstractOAuth2AuthorizationGrantRequest> implements ReactiveOAuth2AccessTokenResponseClient<T> {
  2. private WebClient webClient = WebClient.builder().build();
  3. AbstractWebClientReactiveOAuth2AccessTokenResponseClient() {
  4. }
  5. public Mono<OAuth2AccessTokenResponse> getTokenResponse(T grantRequest) {
  6. Assert.notNull(grantRequest, "grantRequest cannot be null");
  7. return Mono.defer(() -> {
  8. return ((RequestBodySpec)((RequestBodySpec)this.webClient.post().uri(this.clientRegistration(grantRequest).getProviderDetails().getTokenUri(), new Object[0])).headers((headers) -> {
  9. this.populateTokenRequestHeaders(grantRequest, headers);
  10. })).body(this.createTokenRequestBody(grantRequest)).exchange().flatMap((response) -> {
  11. return this.readTokenResponse(grantRequest, response);
  12. });
  13. });
  14. }
  15. abstract ClientRegistration clientRegistration(T var1);
  16. private void populateTokenRequestHeaders(T grantRequest, HttpHeaders headers) {
  17. ClientRegistration clientRegistration = this.clientRegistration(grantRequest);
  18. headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
  19. headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
  20. if (ClientAuthenticationMethod.BASIC.equals(clientRegistration.getClientAuthenticationMethod())) {
  21. headers.setBasicAuth(clientRegistration.getClientId(), clientRegistration.getClientSecret());
  22. }
  23. }
  24. private FormInserter<String> createTokenRequestBody(T grantRequest) {
  25. FormInserter<String> body = BodyInserters.fromFormData("grant_type", grantRequest.getGrantType().getValue());
  26. return this.populateTokenRequestBody(grantRequest, body);
  27. }
  28. FormInserter<String> populateTokenRequestBody(T grantRequest, FormInserter<String> body) {
  29. ClientRegistration clientRegistration = this.clientRegistration(grantRequest);
  30. if (!ClientAuthenticationMethod.BASIC.equals(clientRegistration.getClientAuthenticationMethod())) {
  31. body.with("client_id", clientRegistration.getClientId());
  32. }
  33. if (ClientAuthenticationMethod.POST.equals(clientRegistration.getClientAuthenticationMethod())) {
  34. body.with("client_secret", clientRegistration.getClientSecret());
  35. }
  36. Set<String> scopes = this.scopes(grantRequest);
  37. if (!CollectionUtils.isEmpty(scopes)) {
  38. body.with("scope", StringUtils.collectionToDelimitedString(scopes, " "));
  39. }
  40. return body;
  41. }
  42. abstract Set<String> scopes(T var1);
  43. Set<String> defaultScopes(T grantRequest) {
  44. return this.scopes(grantRequest);
  45. }
  46. private Mono<OAuth2AccessTokenResponse> readTokenResponse(T grantRequest, ClientResponse response) {
  47. return ((Mono)response.body(OAuth2BodyExtractors.oauth2AccessTokenResponse())).map((tokenResponse) -> {
  48. return this.populateTokenResponse(grantRequest, tokenResponse);
  49. });
  50. }
  51. OAuth2AccessTokenResponse populateTokenResponse(T grantRequest, OAuth2AccessTokenResponse tokenResponse) {
  52. if (CollectionUtils.isEmpty(tokenResponse.getAccessToken().getScopes())) {
  53. Set<String> defaultScopes = this.defaultScopes(grantRequest);
  54. tokenResponse = OAuth2AccessTokenResponse.withResponse(tokenResponse).scopes(defaultScopes).build();
  55. }
  56. return tokenResponse;
  57. }
  58. public void setWebClient(WebClient webClient) {
  59. Assert.notNull(webClient, "webClient cannot be null");
  60. this.webClient = webClient;
  61. }
  62. }

 

 

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

闽ICP备14008679号