spring security webflux 三方用户授权登录说明

论坛 期权论坛 脚本     
已经匿名di用户   2022-3-21 23:58   3197   0

spring security webflux 三方用户授权说明

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

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

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

相关类及接口

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

public enum CommonOAuth2Provider {
    GOOGLE {
        public Builder getBuilder(String registrationId) {
            Builder builder = this.getBuilder(registrationId, ClientAuthenticationMethod.BASIC, "{baseUrl}/{action}/oauth2/code/{registrationId}");
            builder.scope(new String[]{"openid", "profile", "email"});
            builder.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth");
            builder.tokenUri("https://www.googleapis.com/oauth2/v4/token");
            builder.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs");
            builder.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo");
            builder.userNameAttributeName("sub");
            builder.clientName("Google");
            return builder;
        }
    },
    GITHUB {
        public Builder getBuilder(String registrationId) {
            Builder builder = this.getBuilder(registrationId, ClientAuthenticationMethod.BASIC, "{baseUrl}/{action}/oauth2/code/{registrationId}");
            builder.scope(new String[]{"read:user"});
            builder.authorizationUri("https://github.com/login/oauth/authorize");
            builder.tokenUri("https://github.com/login/oauth/access_token");
            builder.userInfoUri("https://api.github.com/user");
            builder.userNameAttributeName("id");
            builder.clientName("GitHub");
            return builder;
        }
    },
    FACEBOOK {
        public Builder getBuilder(String registrationId) {
            Builder builder = this.getBuilder(registrationId, ClientAuthenticationMethod.POST, "{baseUrl}/{action}/oauth2/code/{registrationId}");
            builder.scope(new String[]{"public_profile", "email"});
            builder.authorizationUri("https://www.facebook.com/v2.8/dialog/oauth");
            builder.tokenUri("https://graph.facebook.com/v2.8/oauth/access_token");
            builder.userInfoUri("https://graph.facebook.com/me?fields=id,name,email");
            builder.userNameAttributeName("id");
            builder.clientName("Facebook");
            return builder;
        }
    },
    OKTA {
        public Builder getBuilder(String registrationId) {
            Builder builder = this.getBuilder(registrationId, ClientAuthenticationMethod.BASIC, "{baseUrl}/{action}/oauth2/code/{registrationId}");
            builder.scope(new String[]{"openid", "profile", "email"});
            builder.userNameAttributeName("sub");
            builder.clientName("Okta");
            return builder;
        }
    };

    private static final String DEFAULT_REDIRECT_URL = "{baseUrl}/{action}/oauth2/code/{registrationId}";

    private CommonOAuth2Provider() {
    }

    protected final Builder getBuilder(String registrationId, ClientAuthenticationMethod method, String redirectUri) {
        Builder builder = ClientRegistration.withRegistrationId(registrationId);
        builder.clientAuthenticationMethod(method);
        builder.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE);
        builder.redirectUriTemplate(redirectUri);
        return builder;
    }

    public abstract Builder getBuilder(String var1);
}

ServerHttpSecurity:oauth2配置入口类

public class ServerHttpSecurity {


******************
内部类:ServerHttpSecurity.OAuth2LoginSpec

    public class OAuth2LoginSpec {
        private ReactiveClientRegistrationRepository clientRegistrationRepository;  //存储授权提供方
        private ServerOAuth2AuthorizedClientRepository authorizedClientRepository;  //存储授权客户端
        private ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest>  authorizationRequestRepository;  //授权请求操作
        private ReactiveAuthenticationManager authenticationManager;                //获取access_token,成功后加载OAuth2User

        private ServerSecurityContextRepository securityContextRepository;
        private ServerAuthenticationConverter authenticationConverter;
        private ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver;
        private ServerWebExchangeMatcher authenticationMatcher;
        private ServerAuthenticationSuccessHandler authenticationSuccessHandler;
        private ServerAuthenticationFailureHandler authenticationFailureHandler;

        public ServerHttpSecurity.OAuth2LoginSpec authenticationManager(ReactiveAuthenticationManager authenticationManager) {
        public ServerHttpSecurity.OAuth2LoginSpec securityContextRepository(ServerSecurityContextRepository securityContextRepository) {
        public ServerHttpSecurity.OAuth2LoginSpec authenticationSuccessHandler(ServerAuthenticationSuccessHandler authenticationSuccessHandler) {
        public ServerHttpSecurity.OAuth2LoginSpec authenticationFailureHandler(ServerAuthenticationFailureHandler authenticationFailureHandler) {

        private ReactiveAuthenticationManager getAuthenticationManager() {
            if (this.authenticationManager == null) {
                this.authenticationManager = this.createDefault();
            }//如果没有设置authenticationManager,则创建默认的authenticationManager

            return this.authenticationManager;
        }

        private ReactiveAuthenticationManager createDefault() {
            ReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> client = this.getAccessTokenResponseClient();
                                                //获取access_token客户端,如果不存在则创建WebClientReactiveAuthorizationCodeTokenResponseClient

            ReactiveAuthenticationManager result = new OAuth2LoginReactiveAuthenticationManager(client, this.getOauth2UserService());
                                                //创建OAuth2LoginReactiveAuthenticationManager,该对象可同时获取access_token、oauth2User(如果不存在,默认为DefaultReactiveOAuth2UserService对象)

            boolean oidcAuthenticationProviderEnabled = ClassUtils.isPresent("org.springframework.security.oauth2.jwt.JwtDecoder", this.getClass().getClassLoader());
            if (oidcAuthenticationProviderEnabled) {
                OidcAuthorizationCodeReactiveAuthenticationManager oidc = new OidcAuthorizationCodeReactiveAuthenticationManager(client, this.getOidcUserService());
                ResolvableType type = ResolvableType.forClassWithGenerics(ReactiveJwtDecoderFactory.class, new Class[]{ClientRegistration.class});
                ReactiveJwtDecoderFactory<ClientRegistration> jwtDecoderFactory = (ReactiveJwtDecoderFactory)ServerHttpSecurity.this.getBeanOrNull(type);
                if (jwtDecoderFactory != null) {
                    oidc.setJwtDecoderFactory(jwtDecoderFactory);
                }

                result = new DelegatingReactiveAuthenticationManager(new ReactiveAuthenticationManager[]{oidc, (ReactiveAuthenticationManager)result});
            }

            return (ReactiveAuthenticationManager)result;
        }

        public ServerHttpSecurity.OAuth2LoginSpec authenticationConverter(ServerAuthenticationConverter authenticationConverter) {
            this.authenticationConverter = authenticationConverter;
            return this;
        }

        private ServerAuthenticationConverter getAuthenticationConverter(ReactiveClientRegistrationRepository clientRegistrationRepository) {
            if (this.authenticationConverter == null) {
                ServerOAuth2AuthorizationCodeAuthenticationTokenConverter authenticationConverter = new ServerOAuth2AuthorizationCodeAuthenticationTokenConverter(clientRegistrationRepository);
                authenticationConverter.setAuthorizationRequestRepository(this.getAuthorizationRequestRepository());
                this.authenticationConverter = authenticationConverter;
            }

            return this.authenticationConverter;
        }

        public ServerHttpSecurity.OAuth2LoginSpec clientRegistrationRepository(ReactiveClientRegistrationRepository clientRegistrationRepository) {
            this.clientRegistrationRepository = clientRegistrationRepository;
            return this;
        }

        public ServerHttpSecurity.OAuth2LoginSpec authorizedClientService(ReactiveOAuth2AuthorizedClientService authorizedClientService) {
            this.authorizedClientRepository = new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(authorizedClientService);
            return this;
        }

        public ServerHttpSecurity.OAuth2LoginSpec authorizedClientRepository(ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {
        public ServerHttpSecurity.OAuth2LoginSpec authorizationRequestRepository(ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository) {
        public ServerHttpSecurity.OAuth2LoginSpec authorizationRequestResolver(ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver) {
        public ServerHttpSecurity.OAuth2LoginSpec authenticationMatcher(ServerWebExchangeMatcher authenticationMatcher) {

        private ServerWebExchangeMatcher getAuthenticationMatcher() {
            if (this.authenticationMatcher == null) {
                this.authenticationMatcher = this.createAttemptAuthenticationRequestMatcher();
            }  //如果没有设置authenticationManager,则创建默认的authenticationManager

            return this.authenticationMatcher;
        }

        public ServerHttpSecurity and() {
            return ServerHttpSecurity.this;
        }

        protected void configure(ServerHttpSecurity http) {
            ReactiveClientRegistrationRepository clientRegistrationRepository = this.getClientRegistrationRepository();  //获取clientRegistration
            ServerOAuth2AuthorizedClientRepository authorizedClientRepository = this.getAuthorizedClientRepository();    //获取authorizedClient


            OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter = this.getRedirectWebFilter();  //认证请求跳转过滤器,获取授权码
            ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository = this.getAuthorizationRequestRepository();
            oauthRedirectFilter.setAuthorizationRequestRepository(authorizationRequestRepository);
            oauthRedirectFilter.setRequestCache(http.requestCache.requestCache);


            ReactiveAuthenticationManager manager = this.getAuthenticationManager();   //获取access_token、oauth2User
            AuthenticationWebFilter authenticationFilter = new OAuth2LoginAuthenticationWebFilter(manager, authorizedClientRepository);
            authenticationFilter.setRequiresAuthenticationMatcher(this.getAuthenticationMatcher());
            authenticationFilter.setServerAuthenticationConverter(this.getAuthenticationConverter(clientRegistrationRepository));
            authenticationFilter.setAuthenticationSuccessHandler(this.getAuthenticationSuccessHandler(http));
            authenticationFilter.setAuthenticationFailureHandler(this.getAuthenticationFailureHandler());
            authenticationFilter.setSecurityContextRepository(this.securityContextRepository);


            this.setDefaultEntryPoints(http);
            http.addFilterAt(oauthRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC);
            http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION);
        }

        private void setDefaultEntryPoints(ServerHttpSecurity http) {
            String defaultLoginPage = "/login";
            Map<String, String> urlToText = http.oauth2Login.getLinks();
            String providerLoginPage = null;
            if (urlToText.size() == 1) {
                providerLoginPage = (String)urlToText.keySet().iterator().next();
            }

            MediaTypeServerWebExchangeMatcher htmlMatcher = new MediaTypeServerWebExchangeMatcher(new MediaType[]{MediaType.APPLICATION_XHTML_XML, new MediaType("image", "*"), MediaType.TEXT_HTML, MediaType.TEXT_PLAIN});
            htmlMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
            ServerWebExchangeMatcher xhrMatcher = (exchange) -> {
                return exchange.getRequest().getHeaders().getOrEmpty("X-Requested-With").contains("XMLHttpRequest") ? MatchResult.match() : MatchResult.notMatch();
            };
            ServerWebExchangeMatcher notXhrMatcher = new NegatedServerWebExchangeMatcher(xhrMatcher);
            ServerWebExchangeMatcher defaultEntryPointMatcher = new AndServerWebExchangeMatcher(new ServerWebExchangeMatcher[]{notXhrMatcher, htmlMatcher});
            if (providerLoginPage != null) {
                ServerWebExchangeMatcher loginPageMatcher = new PathPatternParserServerWebExchangeMatcher(defaultLoginPage);
                ServerWebExchangeMatcher faviconMatcher = new PathPatternParserServerWebExchangeMatcher("/favicon.ico");
                ServerWebExchangeMatcher defaultLoginPageMatcher = new AndServerWebExchangeMatcher(new ServerWebExchangeMatcher[]{new OrServerWebExchangeMatcher(new ServerWebExchangeMatcher[]{loginPageMatcher, faviconMatcher}), defaultEntryPointMatcher});
                ServerWebExchangeMatcher matcher = new AndServerWebExchangeMatcher(new ServerWebExchangeMatcher[]{notXhrMatcher, new NegatedServerWebExchangeMatcher(defaultLoginPageMatcher)});
                RedirectServerAuthenticationEntryPoint entryPoint = new RedirectServerAuthenticationEntryPoint(providerLoginPage);
                entryPoint.setRequestCache(http.requestCache.requestCache);
                http.defaultEntryPoints.add(new DelegateEntry(matcher, entryPoint));
            }

            RedirectServerAuthenticationEntryPoint defaultEntryPoint = new RedirectServerAuthenticationEntryPoint(defaultLoginPage);
            defaultEntryPoint.setRequestCache(http.requestCache.requestCache);
            http.defaultEntryPoints.add(new DelegateEntry(defaultEntryPointMatcher, defaultEntryPoint));
        }

        private ServerAuthenticationSuccessHandler getAuthenticationSuccessHandler(ServerHttpSecurity http) {
            if (this.authenticationSuccessHandler == null) {
                RedirectServerAuthenticationSuccessHandler handler = new RedirectServerAuthenticationSuccessHandler();
                handler.setRequestCache(http.requestCache.requestCache);
                this.authenticationSuccessHandler = handler;
            }

            return this.authenticationSuccessHandler;
        }

        private ServerAuthenticationFailureHandler getAuthenticationFailureHandler() {
            if (this.authenticationFailureHandler == null) {
                this.authenticationFailureHandler = new RedirectServerAuthenticationFailureHandler("/login?error");
            }

            return this.authenticationFailureHandler;
        }

        private ServerWebExchangeMatcher createAttemptAuthenticationRequestMatcher() {
            return new PathPatternParserServerWebExchangeMatcher("/login/oauth2/code/{registrationId}");
        }

        private ReactiveOAuth2UserService<OidcUserRequest, OidcUser> getOidcUserService() {
            ResolvableType type = ResolvableType.forClassWithGenerics(ReactiveOAuth2UserService.class, new Class[]{OidcUserRequest.class, OidcUser.class});
            ReactiveOAuth2UserService<OidcUserRequest, OidcUser> bean = (ReactiveOAuth2UserService)ServerHttpSecurity.this.getBeanOrNull(type);
            return (ReactiveOAuth2UserService)(bean == null ? new OidcReactiveOAuth2UserService() : bean);
        }

        private ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> getOauth2UserService() {
                                         //获取认证用户操作类
            ResolvableType type = ResolvableType.forClassWithGenerics(ReactiveOAuth2UserService.class, new Class[]{OAuth2UserRequest.class, OAuth2User.class});
            ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> bean = (ReactiveOAuth2UserService)ServerHttpSecurity.this.getBeanOrNull(type);
            return (ReactiveOAuth2UserService)(bean == null ? new DefaultReactiveOAuth2UserService() : bean);
        }

        private Map<String, String> getLinks() {
            Iterable<ClientRegistration> registrations = (Iterable)ServerHttpSecurity.this.getBeanOrNull(ResolvableType.forClassWithGenerics(Iterable.class, new Class[]{ClientRegistration.class}));
            if (registrations == null) {
                return Collections.emptyMap();
            } else {
                Map<String, String> result = new HashMap();
                registrations.iterator().forEachRemaining((r) -> {
                    String var10000 = (String)result.put("/oauth2/authorization/" + r.getRegistrationId(), r.getClientName());
                });
                return result;
            }
        }

        private ReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> getAccessTokenResponseClient() {
            ResolvableType type = ResolvableType.forClassWithGenerics(ReactiveOAuth2AccessTokenResponseClient.class, new Class[]{OAuth2AuthorizationCodeGrantRequest.class});
            ReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> bean = (ReactiveOAuth2AccessTokenResponseClient)ServerHttpSecurity.this.getBeanOrNull(type);
            return (ReactiveOAuth2AccessTokenResponseClient)(bean == null ? new WebClientReactiveAuthorizationCodeTokenResponseClient() : bean);
        }

        private ReactiveClientRegistrationRepository getClientRegistrationRepository() {
            if (this.clientRegistrationRepository == null) {
                this.clientRegistrationRepository = (ReactiveClientRegistrationRepository)ServerHttpSecurity.this.getBeanOrNull(ReactiveClientRegistrationRepository.class);
            }

            return this.clientRegistrationRepository;
        }

        private OAuth2AuthorizationRequestRedirectWebFilter getRedirectWebFilter() {
            OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter;
            if (this.authorizationRequestResolver == null) {
                oauthRedirectFilter = new OAuth2AuthorizationRequestRedirectWebFilter(this.getClientRegistrationRepository());
            } else {
                oauthRedirectFilter = new OAuth2AuthorizationRequestRedirectWebFilter(this.authorizationRequestResolver);
            }

            return oauthRedirectFilter;
        }

        private ServerOAuth2AuthorizedClientRepository getAuthorizedClientRepository() {
            ServerOAuth2AuthorizedClientRepository result = this.authorizedClientRepository;
            if (result == null) {
                result = (ServerOAuth2AuthorizedClientRepository)ServerHttpSecurity.this.getBeanOrNull(ServerOAuth2AuthorizedClientRepository.class);
            }

            if (result == null) {
                ReactiveOAuth2AuthorizedClientService authorizedClientService = this.getAuthorizedClientService();
                if (authorizedClientService != null) {
                    result = new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(authorizedClientService);
                }
            }

            return (ServerOAuth2AuthorizedClientRepository)result;
        }

        private ServerAuthorizationRequestRepository<OAuth2AuthorizationRequest> getAuthorizationRequestRepository() {
            if (this.authorizationRequestRepository == null) {
                this.authorizationRequestRepository = new WebSessionOAuth2ServerAuthorizationRequestRepository();
            }

            return this.authorizationRequestRepository;
        }

        private ReactiveOAuth2AuthorizedClientService getAuthorizedClientService() {
            ReactiveOAuth2AuthorizedClientService service = (ReactiveOAuth2AuthorizedClientService)ServerHttpSecurity.this.getBeanOrNull(ReactiveOAuth2AuthorizedClientService.class);
            if (service == null) {
                service = new InMemoryReactiveOAuth2AuthorizedClientService(this.getClientRegistrationRepository());
            }

            return (ReactiveOAuth2AuthorizedClientService)service;
        }

        private OAuth2LoginSpec() {
        }
    }

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

ReactiveClientRegistrationRepository

ReactiveClientRegistrationRepository:存储授权提供方

public interface ReactiveClientRegistrationRepository {
    Mono<ClientRegistration> findByRegistrationId(String var1);
}

InMemoryReactiveClientRegistrationRepository:内存中存储clientRegistration

public final class InMemoryReactiveClientRegistrationRepository implements ReactiveClientRegistrationRepository, Iterable<ClientRegistration> {
    private final Map<String, ClientRegistration> clientIdToClientRegistration;

    public InMemoryReactiveClientRegistrationRepository(ClientRegistration... registrations) {
        this(toList(registrations));
    }

    private static List<ClientRegistration> toList(ClientRegistration... registrations) {
        Assert.notEmpty(registrations, "registrations cannot be null or empty");
        return Arrays.asList(registrations);
    }

    public InMemoryReactiveClientRegistrationRepository(List<ClientRegistration> registrations) {
        this.clientIdToClientRegistration = toUnmodifiableConcurrentMap(registrations);
    }

    public Mono<ClientRegistration> findByRegistrationId(String registrationId) {
        return Mono.justOrEmpty(this.clientIdToClientRegistration.get(registrationId));
    }

    public Iterator<ClientRegistration> iterator() {
        return this.clientIdToClientRegistration.values().iterator();
    }

    private static Map<String, ClientRegistration> toUnmodifiableConcurrentMap(List<ClientRegistration> registrations) {
        Assert.notEmpty(registrations, "registrations cannot be null or empty");
        ConcurrentHashMap<String, ClientRegistration> result = new ConcurrentHashMap();
        Iterator var2 = registrations.iterator();

        while(var2.hasNext()) {
            ClientRegistration registration = (ClientRegistration)var2.next();
            Assert.notNull(registration, "no registration can be null");
            if (result.containsKey(registration.getRegistrationId())) {
                throw new IllegalStateException(String.format("Duplicate key %s", registration.getRegistrationId()));
            }

            result.put(registration.getRegistrationId(), registration);
        }

        return Collections.unmodifiableMap(result);
    }
}

clientRegistration:clientRegistration属性

public final class ClientRegistration implements Serializable {
    private static final long serialVersionUID = 530L;
    private String registrationId;
    private String clientId;
    private String clientSecret;
    private ClientAuthenticationMethod clientAuthenticationMethod;
    private AuthorizationGrantType authorizationGrantType;
    private String redirectUriTemplate;
    private Set<String> scopes;
    private ClientRegistration.ProviderDetails providerDetails;
    private String clientName;


***********
内部类:ClientRegistration.ProviderDetails

    public class ProviderDetails implements Serializable {
        private static final long serialVersionUID = 530L;
        private String authorizationUri;
        private String tokenUri;
        private ClientRegistration.ProviderDetails.UserInfoEndpoint userInfoEndpoint;
        private String jwkSetUri;
        private Map<String, Object> configurationMetadata;

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

authenticationManager

ReactiveAuthenticationManager:认证authentication接口

@FunctionalInterface
public interface ReactiveAuthenticationManager {
    Mono<Authentication> authenticate(Authentication var1);
}

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

public class OAuth2LoginReactiveAuthenticationManager implements ReactiveAuthenticationManager {
    private final ReactiveAuthenticationManager authorizationCodeManager;
    private final ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> userService;
    private GrantedAuthoritiesMapper authoritiesMapper = (authorities) -> {
        return authorities;
    };

    public OAuth2LoginReactiveAuthenticationManager(ReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient, ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> userService) {
        Assert.notNull(accessTokenResponseClient, "accessTokenResponseClient cannot be null");
        Assert.notNull(userService, "userService cannot be null");
        this.authorizationCodeManager = new OAuth2AuthorizationCodeReactiveAuthenticationManager(accessTokenResponseClient);
        this.userService = userService;
    }

    public Mono<Authentication> authenticate(Authentication authentication) {
                                //认证authentication

        return Mono.defer(() -> {
            OAuth2AuthorizationCodeAuthenticationToken token = (OAuth2AuthorizationCodeAuthenticationToken)authentication;
            return token.getAuthorizationExchange().getAuthorizationRequest().getScopes().contains("openid") ? Mono.empty() : this.authorizationCodeManager.authenticate(token).onErrorMap(OAuth2AuthorizationException.class, (e) -> {
                return new OAuth2AuthenticationException(e.getError(), e.getError().toString());
            }).cast(OAuth2AuthorizationCodeAuthenticationToken.class).flatMap(this::onSuccess);
        });
    }

    private Mono<OAuth2LoginAuthenticationToken> onSuccess(OAuth2AuthorizationCodeAuthenticationToken authentication) {
                                 //认证成功后,加载认证用户
        OAuth2AccessToken accessToken = authentication.getAccessToken();
        Map<String, Object> additionalParameters = authentication.getAdditionalParameters();
        OAuth2UserRequest userRequest = new OAuth2UserRequest(authentication.getClientRegistration(), accessToken, additionalParameters);
        return this.userService.loadUser(userRequest).map((oauth2User) -> {
            Collection<? extends GrantedAuthority> mappedAuthorities = this.authoritiesMapper.mapAuthorities(oauth2User.getAuthorities());
            OAuth2LoginAuthenticationToken authenticationResult = new OAuth2LoginAuthenticationToken(authentication.getClientRegistration(), authentication.getAuthorizationExchange(), oauth2User, mappedAuthorities, accessToken, authentication.getRefreshToken());
            return authenticationResult;
        });
    }
}

ReactiveOAuth2UserService:加载认证用户接口

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

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

public class DefaultReactiveOAuth2UserService implements ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> {
    private static final String INVALID_USER_INFO_RESPONSE_ERROR_CODE = "invalid_user_info_response";
    private static final String MISSING_USER_INFO_URI_ERROR_CODE = "missing_user_info_uri";
    private static final String MISSING_USER_NAME_ATTRIBUTE_ERROR_CODE = "missing_user_name_attribute";
    private WebClient webClient = WebClient.create();

    public DefaultReactiveOAuth2UserService() {
    }

    public Mono<OAuth2User> loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
                            //加载认证用户
        return Mono.defer(() -> {
            Assert.notNull(userRequest, "userRequest cannot be null");
            String userInfoUri = userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri();
            if (!StringUtils.hasText(userInfoUri)) {
                OAuth2Error oauth2Error = new OAuth2Error("missing_user_info_uri", "Missing required UserInfo Uri in UserInfoEndpoint for Client Registration: " + userRequest.getClientRegistration().getRegistrationId(), (String)null);
                throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
            } else {
                String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName();
                if (!StringUtils.hasText(userNameAttributeName)) {
                    OAuth2Error oauth2Errorx = new OAuth2Error("missing_user_name_attribute", "Missing required \"user name\" attribute name in UserInfoEndpoint for Client Registration: " + userRequest.getClientRegistration().getRegistrationId(), (String)null);
                    throw new OAuth2AuthenticationException(oauth2Errorx, oauth2Errorx.toString());
                } else {
                    ParameterizedTypeReference<Map<String, Object>> typeReference = new ParameterizedTypeReference<Map<String, Object>>() {
                    };
                    AuthenticationMethod authenticationMethod = userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getAuthenticationMethod();
                    RequestHeadersSpec requestHeadersSpec;
                    if (AuthenticationMethod.FORM.equals(authenticationMethod)) {
                        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());
                    } else {
                        requestHeadersSpec = this.webClient.get().uri(userInfoUri, new Object[0]).header("Accept", new String[]{"application/json"}).headers((headers) -> {
                            headers.setBearerAuth(userRequest.getAccessToken().getTokenValue());
                        });
                    }

                    Mono<Map<String, Object>> userAttributes = requestHeadersSpec.retrieve().onStatus((s) -> {
                        return s != HttpStatus.OK;
                    }, (response) -> {
                        return parse(response).map((userInfoErrorResponse) -> {
                            String description = userInfoErrorResponse.getErrorObject().getDescription();
                            OAuth2Error oauth2Error = new OAuth2Error("invalid_user_info_response", description, (String)null);
                            throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
                        });
                    }).bodyToMono(typeReference);
                    return userAttributes.map((attrs) -> {
                        GrantedAuthority authority = new OAuth2UserAuthority(attrs);
                        Set<GrantedAuthority> authorities = new HashSet();
                        authorities.add(authority);
                        OAuth2AccessToken token = userRequest.getAccessToken();
                        Iterator var6 = token.getScopes().iterator();

                        while(var6.hasNext()) {
                            String scope = (String)var6.next();
                            authorities.add(new SimpleGrantedAuthority("SCOPE_" + scope));
                        }

                        return new DefaultOAuth2User(authorities, attrs, userNameAttributeName);
                    }).onErrorMap((e) -> {
                        return e instanceof IOException;
                    }, (t) -> {
                        return new AuthenticationServiceException("Unable to access the userInfoEndpoint " + userInfoUri, t);
                    }).onErrorMap((t) -> {
                        return !(t instanceof AuthenticationServiceException);
                    }, (t) -> {
                        OAuth2Error oauth2Error = new OAuth2Error("invalid_user_info_response", "An error occurred reading the UserInfo Success response: " + t.getMessage(), (String)null);
                        return new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), t);
                    });
                }
            }
        });
    }

    public void setWebClient(WebClient webClient) {
        Assert.notNull(webClient, "webClient cannot be null");
        this.webClient = webClient;
    }

    private static Mono<UserInfoErrorResponse> parse(ClientResponse httpResponse) {
        String wwwAuth = httpResponse.headers().asHttpHeaders().getFirst("WWW-Authenticate");
        if (!StringUtils.isEmpty(wwwAuth)) {
            return Mono.fromCallable(() -> {
                return UserInfoErrorResponse.parse(wwwAuth);
            });
        } else {
            ParameterizedTypeReference<Map<String, String>> typeReference = new ParameterizedTypeReference<Map<String, String>>() {
            };
            return httpResponse.bodyToMono(typeReference).map((body) -> {
                return new UserInfoErrorResponse(ErrorObject.parse(new JSONObject(body)));
            });
        }
    }
}

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

获取 access_token

WebClientReactiveAuthorizationCodeTokenResponseClient:获取access_token的客户端

public class WebClientReactiveAuthorizationCodeTokenResponseClient extends AbstractWebClientReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> {
    public WebClientReactiveAuthorizationCodeTokenResponseClient() {
    }

    ClientRegistration clientRegistration(OAuth2AuthorizationCodeGrantRequest grantRequest) {
        return grantRequest.getClientRegistration();
    }

    Set<String> scopes(OAuth2AuthorizationCodeGrantRequest grantRequest) {
        return Collections.emptySet();
    }

    Set<String> defaultScopes(OAuth2AuthorizationCodeGrantRequest grantRequest) {
        return grantRequest.getAuthorizationExchange().getAuthorizationRequest().getScopes();
    }

    FormInserter<String> populateTokenRequestBody(OAuth2AuthorizationCodeGrantRequest grantRequest, FormInserter<String> body) {
        super.populateTokenRequestBody(grantRequest, body);
        OAuth2AuthorizationExchange authorizationExchange = grantRequest.getAuthorizationExchange();
        OAuth2AuthorizationResponse authorizationResponse = authorizationExchange.getAuthorizationResponse();
        body.with("code", authorizationResponse.getCode());
        String redirectUri = authorizationExchange.getAuthorizationRequest().getRedirectUri();
        if (redirectUri != null) {
            body.with("redirect_uri", redirectUri);
        }

        String codeVerifier = (String)authorizationExchange.getAuthorizationRequest().getAttribute("code_verifier");
        if (codeVerifier != null) {
            body.with("code_verifier", codeVerifier);
        }

        return body;
    }
}

AbstractWebClientOAuth2ReactiveAccessTokenResponseClient:使用webClient获取acccess_token

abstract class AbstractWebClientReactiveOAuth2AccessTokenResponseClient<T extends AbstractOAuth2AuthorizationGrantRequest> implements ReactiveOAuth2AccessTokenResponseClient<T> {
    private WebClient webClient = WebClient.builder().build();

    AbstractWebClientReactiveOAuth2AccessTokenResponseClient() {
    }

    public Mono<OAuth2AccessTokenResponse> getTokenResponse(T grantRequest) {
        Assert.notNull(grantRequest, "grantRequest cannot be null");
        return Mono.defer(() -> {
            return ((RequestBodySpec)((RequestBodySpec)this.webClient.post().uri(this.clientRegistration(grantRequest).getProviderDetails().getTokenUri(), new Object[0])).headers((headers) -> {
                this.populateTokenRequestHeaders(grantRequest, headers);
            })).body(this.createTokenRequestBody(grantRequest)).exchange().flatMap((response) -> {
                return this.readTokenResponse(grantRequest, response);
            });
        });
    }

    abstract ClientRegistration clientRegistration(T var1);

    private void populateTokenRequestHeaders(T grantRequest, HttpHeaders headers) {
        ClientRegistration clientRegistration = this.clientRegistration(grantRequest);
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
        if (ClientAuthenticationMethod.BASIC.equals(clientRegistration.getClientAuthenticationMethod())) {
            headers.setBasicAuth(clientRegistration.getClientId(), clientRegistration.getClientSecret());
        }

    }

    private FormInserter<String> createTokenRequestBody(T grantRequest) {
        FormInserter<String> body = BodyInserters.fromFormData("grant_type", grantRequest.getGrantType().getValue());
        return this.populateTokenRequestBody(grantRequest, body);
    }

    FormInserter<String> populateTokenRequestBody(T grantRequest, FormInserter<String> body) {
        ClientRegistration clientRegistration = this.clientRegistration(grantRequest);
        if (!ClientAuthenticationMethod.BASIC.equals(clientRegistration.getClientAuthenticationMethod())) {
            body.with("client_id", clientRegistration.getClientId());
        }

        if (ClientAuthenticationMethod.POST.equals(clientRegistration.getClientAuthenticationMethod())) {
            body.with("client_secret", clientRegistration.getClientSecret());
        }

        Set<String> scopes = this.scopes(grantRequest);
        if (!CollectionUtils.isEmpty(scopes)) {
            body.with("scope", StringUtils.collectionToDelimitedString(scopes, " "));
        }

        return body;
    }

    abstract Set<String> scopes(T var1);

    Set<String> defaultScopes(T grantRequest) {
        return this.scopes(grantRequest);
    }

    private Mono<OAuth2AccessTokenResponse> readTokenResponse(T grantRequest, ClientResponse response) {
        return ((Mono)response.body(OAuth2BodyExtractors.oauth2AccessTokenResponse())).map((tokenResponse) -> {
            return this.populateTokenResponse(grantRequest, tokenResponse);
        });
    }

    OAuth2AccessTokenResponse populateTokenResponse(T grantRequest, OAuth2AccessTokenResponse tokenResponse) {
        if (CollectionUtils.isEmpty(tokenResponse.getAccessToken().getScopes())) {
            Set<String> defaultScopes = this.defaultScopes(grantRequest);
            tokenResponse = OAuth2AccessTokenResponse.withResponse(tokenResponse).scopes(defaultScopes).build();
        }

        return tokenResponse;
    }

    public void setWebClient(WebClient webClient) {
        Assert.notNull(webClient, "webClient cannot be null");
        this.webClient = webClient;
    }
}

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:81
帖子:4969
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP