春季安全OAuth2(谷歌)网络应用程序在重定向循环 [英] Spring Security OAuth2 (google) web app in redirect loop

查看:530
本文介绍了春季安全OAuth2(谷歌)网络应用程序在重定向循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试构建Spring MVC应用程序,并使用Spring Security OAuth2来保护它,而提供者是Google。我能够在没有安全性和表单登录的情况下运行网络应用程序。不过,我无法使用谷歌的OAuth工作。谷歌应用程序设置是好的,因为我可以让回调等与非Spring安全应用程序一起工作。



我的安全配置如下

 <?xml version =1.0encoding =UTF-8?> 
< b:beans xmlns:sec =http://www.springframework.org/schema/security
xmlns:b =http://www.springframework.org/schema/beans
xmlns:xsi =http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation =http://www.springframework.org/schema/beans http: //www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/弹簧security.xsd>
< sec:http-basic />
< sec:logout />
< sec:anonymous enabled =false/>

< sec:intercept-url pattern =/ **access =isFullyAuthenticated()/>

< sec:custom = filter ref =oauth2ClientContextFilterafter =EXCEPTION_TRANSLATION_FILTER/>
< sec:custom = filter ref =googleAuthenticationFilterbefore =FILTER_SECURITY_INTERCEPTOR/>
< / sec:http>

< b:bean id =clientAuthenticationEntryPointclass =org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint/>

< sec:认证提供者>
< sec:用户服务>
< sec:user name =userpassword =passwordauthorities =DOMAIN_USER/>
< / sec:用户服务>
< / sec:authentication-provider>
< / sec:authentication-manager>
< / b:beans>

受OAuth2保护的资源如下

 @Configuration 
@ EnableOAuth2Client
类ResourceConfiguration {
@Autowired
private环境env;

@Resource
@Qualifier(accessTokenRequest)
private AccessTokenRequest accessTokenRequest;

@Bean
public OAuth2ProtectedResourceDetails googleResource(){
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
details.setId(google-app);
details.setClientId(env.getProperty(google.client.id));
details.setClientSecret(env.getProperty(google.client.secret));
details.setAccessTokenUri(env.getProperty(google.accessTokenUri));
details.setUserAuthorizationUri(env.getProperty(google.userAuthorizationUri));
details.setTokenName(env.getProperty(google.authorization.code));
String commaSeparatedScopes = env.getProperty(google.auth.scope);
details.setScope(parseScopes(commaSeparatedScopes));
details.setPreEstablishedRedirectUri(env.getProperty(google.preestablished.redirect.url));
details.setUseCurrentUri(false);
details.setAuthenticationScheme(AuthenticationScheme.query);
details.setClientAuthenticationScheme(AuthenticationScheme.form);
返回细节;
}

私人列表< String> parseScopes(String commaSeparatedScopes){
List< String> scopes = newArrayList();
Collections.addAll(scopes,commaSeparatedScopes.split(,));
返回范围;
}

@Bean
public OAuth2RestTemplate googleRestTemplate(){
return new OAuth2RestTemplate(googleResource(),new DefaultOAuth2ClientContext(accessTokenRequest));

$ b @Bean
public AbstractAuthenticationProcessingFilter googleAuthenticationFilter(){
返回新的GoogleOAuthentication2Filter(新的GoogleAppsDomainAuthenticationManager(),googleRestTemplate(),https://accounts.google .com / o / oauth2 / auth,http:// localhost:9000);


我写的自定义验证过滤器抛出重定向异常获得OAuth2授权如下所示:

  @Override 
public Authentication attemptAuthentication(HttpServletRequest请求,HttpServletResponse响应) throws AuthenticationException,IOException,ServletException {
try {
logger.info(OAuth2 Filter Triggered !! for path {} {},request.getRequestURI(),request.getRequestURL()。toString() );
logger.info(OAuth2 Filter hashCode {} request hashCode {},this.hashCode(),request.hashCode());
String code = request.getParameter(code);
身份验证身份验证= SecurityContextHolder.getContext()。getAuthentication();
logger.info(Code is {} and authentication is {},code,authentication == null?null:authentication.isAuthenticated());
//未经过认证
if(requiresRedirectForAuthentication(code)){
URI authURI = new URI(googleAuthorizationUrl);

logger.info(发布到{}以触发auth重定向,authURI);
String url =https://www.googleapis.com/oauth2/v2/userinfo?access_token=+ oauth2RestTemplate.getAccessToken();
logger.info(从{}获取个人资料数据,url);
//应抛出RedirectRequiredException
oauth2RestTemplate.getForEntity(url,GoogleProfile.class);

//认证正在进行中
返回null;
} else {
logger.info(OAuth callback received);
//获取用户配置文件并准备身份验证令牌对象。

String url =https://www.googleapis.com/oauth2/v2/userinfo?access_token=+ oauth2RestTemplate.getAccessToken();
logger.info(从{}获取个人资料数据,url);
ResponseEntity< GoogleProfile> forEntity = oauth2RestTemplate.getForEntity(url,GoogleProfile.class);
GoogleProfile配置文件= forEntity.getBody();

CustomOAuth2AuthenticationToken authenticationToken = getOAuth2Token(profile.getEmail());
authenticationToken.setAuthenticated(false);
Authentication authenticate = getAuthenticationManager()。authenticate(authenticationToken);
logger.info(Final authentication is {},authenticate == null?null:authenticate.isAuthenticated());

return authenticate;
}
} catch(URISyntaxException e){
Throwables.propagate(e);
}
返回null;
}

Spring web应用程序的过滤器链序列如下所示


$ b $

  osbceServletRegistrationBean  - 映射servlet:'dispatcherServlet'到[/] 
osbceFilterRegistrationBean - 映射过滤器:'metricFilter'到:[/ *]
osbceFilterRegistrationBean - 映射过滤器:'oauth2ClientContextFilter'至:[/ *]
osbceFilterRegistrationBean - 映射过滤器:'googleOAuthFilter'至:[/ *]
osbceFilterRegistrationBean - 映射过滤器: 'org.springframework.security.filterChainProxy'to:[/ *]
osbceFilterRegistrationBean - 映射过滤器:'org.springframework.security.web.access.intercept.FilterSecurityInterceptor#0'到:[/ *]
osbceFilterRegistrationBean映射过滤器'hiddenHttpMethodFilter'到:[/ *]
osbceFilterRegistrationBean - 映射过滤器:'applicationContextIdFilter'到:[/ *]
osbceFilterRegistrationBean - Mapp ing过滤器:'webRequestLoggingFilter':[/ *]

重定向到Google工作正常,过滤器的回调和认证成功。然而之后,请求会产生重定向,并再次调用过滤器(请求相同,我已经检查过hasCode)。在第二次调用时,SecurityContext中的身份验证为空。作为第一次身份验证调用的一部分,身份验证对象已填充到安全上下文中,为何它会消失?
我正在和Spring Security第一次合作,所以可能会犯新手错误。

解决方案

Spring Security配置和过滤器我终于能够得到这个工作。我必须做出几个重要的改变。我使用了一个标准的Spring OAuth2过滤器( org.springframework.security。)。 oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter )而不是我正在使用的自定义过滤器。

  • 将认证过滤器的拦截URL更改为 / googleLogin 并添加了一个认证入口点,该认证入口点在认证失败时重定向到此URL。 >整体流程如下:

    • 浏览器访问 / 和当上下文不匹配时,请求将通过 OAuth2ClientContextFilter OAuth2ClientAuthenticationProcessingFilter 进行传递。配置的登录路径是 / googleLogin

    • 安全拦截器 FilterSecurityInterceptor 检测到用户是匿名的并抛出一个拒绝访问的异常。

    • Spring安全的 ExceptionTranslationFilter 捕获拒绝访问异常并询问配置身份验证入口点来处理它发出重定向到 / googleLogin

    • 对于请求 / googleLogin ,过滤器 OAuth2AuthenticationProcessingFilter 会尝试访问Google受保护的资源,并抛出 UserRedirectRequiredException 通过 OAuth2ClientContextFilter 转换为Google的HTTP重定向(使用OAuth2详细信息)。

    • 成功通过Google验证后,浏览器被重定向回到 / googleLogin 与OAuth代码。过滤器 OAuth2AuthenticationProcessingFilter 处理这个并创建一个认证对象并更新 SecurityContext

    • 此时,用户完全通过身份验证,并由 OAuth2AuthenticationProcessingFilter 发出重定向。

    • FilterSecurityInterceptor 允许请求继续进行,因为 SecurityContext 包含一个认证对象,这是经过认证的。
    • 最后,使用诸如 isFullyAuthenticated()或类似表达式的表达式保护的应用程序页面被呈现。


    安全上下文xml如下:

     < sec:http use-expressions =trueentry-point-ref =clientAuthenticationEntryPoint> 
    < sec:http-basic />
    < sec:logout />
    < sec:anonymous enabled =false/>

    < sec:intercept-url pattern =/ **access =isFullyAuthenticated()/>

    <! - 这是关键部分,接线非常重要 - >
    <! -
    这些过滤器执行的顺序非常重要。 oauth2ClientContextFilter必须在
    之前被调用oAuth2AuthenticationProcessingFilter,这是因为当需要重定向到Google时,oAuth2AuthenticationProcessingFilter
    抛出一个UserRedirectException,oauth2ClientContextFilter处理并生成一个重定向请求给Google。
    随后,来自Google的响应由oAuth2AuthenticationProcessingFilter处理,以填充
    Authentication对象并存储在SecurityContext
    - >
    < sec:custom = filter ref =oauth2ClientContextFilterafter =EXCEPTION_TRANSLATION_FILTER/>
    < sec:custom = filter ref =oAuth2AuthenticationProcessingFilterbefore =FILTER_SECURITY_INTERCEPTOR/>
    < / sec:http>

    < b:bean id =oAuth2AuthenticationProcessingFilterclass =org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter>
    < b:属性名称=restTemplateref =googleRestTemplate/>
    < b:属性名称=tokenServicesref =tokenServices/>
    < / b:bean>

    <! - -
    这些标记类大多是Spring类的一个克隆,但其结构已被修改,以便可以处理来自Google的响应

    - >
    < b:bean id =tokenServicesclass =com.rst.oauth2.google.security.GoogleTokenServices>
    < b:属性名称=checkTokenEndpointUrlvalue =https://www.googleapis.com/oauth2/v1/tokeninfo/>
    < b:property name =clientIdvalue =$ {google.client.id}/>
    < b:属性名称=accessTokenConverter>
    < b:bean class =com.rst.oauth2.google.security.GoogleAccessTokenConverter>
    < b:属性名称=userTokenConverter>
    < b:bean class =com.rst.oauth2.google.security.DefaultUserAuthenticationConverter/>
    < / b:属性>
    < / b:bean>
    < / b:属性>
    < / b:bean>

    <! - -
    此认证入口点用于将所有未经身份验证或未授权的会话定向到
    / googleLogin URL,然后由oAuth2AuthenticationProcessingFilter拦截从
    Google触发认证。
    - >
    < b:bean id =clientAuthenticationEntryPointclass =org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint>
    < b:属性名称=loginFormUrlvalue =/ googleLogin/>
    < / b:bean>

    另外,OAuth2资源的Java Config如下所示:

      @Configuration 
    @ EnableOAuth2Client
    class OAuth2SecurityConfiguration {
    @Autowired
    private Environment env;

    @Resource
    @Qualifier(accessTokenRequest)
    private AccessTokenRequest accessTokenRequest;

    @Bean
    @Scope(session)
    public OAuth2ProtectedResourceDetails googleResource(){
    AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
    details.setId(google-oauth-client);
    details.setClientId(env.getProperty(google.client.id));
    details.setClientSecret(env.getProperty(google.client.secret));
    details.setAccessTokenUri(env.getProperty(google.accessTokenUri));
    details.setUserAuthorizationUri(env.getProperty(google.userAuthorizationUri));
    details.setTokenName(env.getProperty(google.authorization.code));
    String commaSeparatedScopes = env.getProperty(google.auth.scope);
    details.setScope(parseScopes(commaSeparatedScopes));
    details.setPreEstablishedRedirectUri(env.getProperty(google.preestablished.redirect.url));
    details.setUseCurrentUri(false);
    details.setAuthenticationScheme(AuthenticationScheme.query);
    details.setClientAuthenticationScheme(AuthenticationScheme.form);
    返回细节;
    }

    私人列表< String> parseScopes(String commaSeparatedScopes){
    List< String> scopes = newArrayList();
    Collections.addAll(scopes,commaSeparatedScopes.split(,));
    返回范围;

    $ b $Bean
    @Scope(value =session,proxyMode = ScopedProxyMode.INTERFACES)
    public OAuth2RestTemplate googleRestTemplate(){
    return new OAuth2RestTemplate(googleResource(),新的DefaultOAuth2ClientContext(accessTokenRequest));


    $ / code>

    我不得不重写一些Spring类,来自Google的令牌格式与Spring预期的格式不匹配。所以这里需要一些定制手工。


    I am trying to build a Spring MVC application and securing it with Spring Security OAuth2 and the provider is Google. I was able to get the web app working without security and with form login. However I am not able to get OAuth with google to work. Google app setup is fine as I can get the call backs etc to work with a non Spring Security app.

    My security config is as follows

    <?xml version="1.0" encoding="UTF-8"?>
    <b:beans xmlns:sec="http://www.springframework.org/schema/security"
             xmlns:b="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                            http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
        <sec:http use-expressions="true" entry-point-ref="clientAuthenticationEntryPoint">
            <sec:http-basic/>
            <sec:logout/>
            <sec:anonymous enabled="false"/>
    
            <sec:intercept-url pattern="/**" access="isFullyAuthenticated()"/>
    
            <sec:custom-filter ref="oauth2ClientContextFilter" after="EXCEPTION_TRANSLATION_FILTER"/>
            <sec:custom-filter ref="googleAuthenticationFilter" before="FILTER_SECURITY_INTERCEPTOR"/>
        </sec:http>
    
        <b:bean id="clientAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint"/>
    
        <sec:authentication-manager alias="alternateAuthenticationManager">
            <sec:authentication-provider>
                <sec:user-service>
                    <sec:user name="user" password="password" authorities="DOMAIN_USER"/>
                </sec:user-service>
            </sec:authentication-provider>
        </sec:authentication-manager>
    </b:beans>
    

    The OAuth2 protected resource is as follows

    @Configuration
    @EnableOAuth2Client
    class ResourceConfiguration {
        @Autowired
        private Environment env;
    
        @Resource
        @Qualifier("accessTokenRequest")
        private AccessTokenRequest accessTokenRequest;
    
        @Bean
        public OAuth2ProtectedResourceDetails googleResource() {
            AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
            details.setId("google-app");
            details.setClientId(env.getProperty("google.client.id"));
            details.setClientSecret(env.getProperty("google.client.secret"));
            details.setAccessTokenUri(env.getProperty("google.accessTokenUri"));
            details.setUserAuthorizationUri(env.getProperty("google.userAuthorizationUri"));
            details.setTokenName(env.getProperty("google.authorization.code"));
            String commaSeparatedScopes = env.getProperty("google.auth.scope");
            details.setScope(parseScopes(commaSeparatedScopes));
            details.setPreEstablishedRedirectUri(env.getProperty("google.preestablished.redirect.url"));
            details.setUseCurrentUri(false);
            details.setAuthenticationScheme(AuthenticationScheme.query);
            details.setClientAuthenticationScheme(AuthenticationScheme.form);
            return details;
        }
    
        private List<String> parseScopes(String commaSeparatedScopes) {
            List<String> scopes = newArrayList();
            Collections.addAll(scopes, commaSeparatedScopes.split(","));
            return scopes;
        }
    
        @Bean
        public OAuth2RestTemplate googleRestTemplate() {
            return new OAuth2RestTemplate(googleResource(), new DefaultOAuth2ClientContext(accessTokenRequest));
        }
    
        @Bean
        public AbstractAuthenticationProcessingFilter googleAuthenticationFilter() {
            return new GoogleOAuthentication2Filter(new GoogleAppsDomainAuthenticationManager(), googleRestTemplate(), "https://accounts.google.com/o/oauth2/auth", "http://localhost:9000");
        }
    }
    

    The custom authentication filter which I have written to throw a Redirect exception to get the OAuth2 authorisation is as follows

        @Override
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
            try {
                logger.info("OAuth2 Filter Triggered!! for path {} {}", request.getRequestURI(), request.getRequestURL().toString());
                logger.info("OAuth2 Filter hashCode {} request hashCode {}", this.hashCode(), request.hashCode());
                String code = request.getParameter("code");
                Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
                logger.info("Code is {} and authentication is {}", code, authentication == null ? null : authentication.isAuthenticated());
                // not authenticated
                if (requiresRedirectForAuthentication(code)) {
                    URI authURI = new URI(googleAuthorizationUrl);
    
                    logger.info("Posting to {} to trigger auth redirect", authURI);
                    String url = "https://www.googleapis.com/oauth2/v2/userinfo?access_token=" + oauth2RestTemplate.getAccessToken();
                    logger.info("Getting profile data from {}", url);
                    // Should throw RedirectRequiredException
                    oauth2RestTemplate.getForEntity(url, GoogleProfile.class);
    
                    // authentication in progress
                    return null;
                } else {
                    logger.info("OAuth callback received");
                    // get user profile and prepare the authentication token object.
    
                    String url = "https://www.googleapis.com/oauth2/v2/userinfo?access_token=" + oauth2RestTemplate.getAccessToken();
                    logger.info("Getting profile data from {}", url);
                    ResponseEntity<GoogleProfile> forEntity = oauth2RestTemplate.getForEntity(url, GoogleProfile.class);
                    GoogleProfile profile = forEntity.getBody();
    
                    CustomOAuth2AuthenticationToken authenticationToken = getOAuth2Token(profile.getEmail());
                    authenticationToken.setAuthenticated(false);
                    Authentication authenticate = getAuthenticationManager().authenticate(authenticationToken);
                    logger.info("Final authentication is {}", authenticate == null ? null : authenticate.isAuthenticated());
    
                    return authenticate;
                }
            } catch (URISyntaxException e) {
                Throwables.propagate(e);
            }
            return null;
        }
    

    The filter chain sequence from the Spring web app is as follows

    o.s.b.c.e.ServletRegistrationBean - Mapping servlet: 'dispatcherServlet' to [/] 
    o.s.b.c.e.FilterRegistrationBean - Mapping filter: 'metricFilter' to: [/*] 
    o.s.b.c.e.FilterRegistrationBean - Mapping filter: 'oauth2ClientContextFilter' to: [/*] 
    o.s.b.c.e.FilterRegistrationBean - Mapping filter: 'googleOAuthFilter' to: [/*] 
    o.s.b.c.e.FilterRegistrationBean - Mapping filter: 'org.springframework.security.filterChainProxy' to: [/*] 
    o.s.b.c.e.FilterRegistrationBean - Mapping filter: 'org.springframework.security.web.access.intercept.FilterSecurityInterceptor#0' to: [/*] 
    o.s.b.c.e.FilterRegistrationBean - Mapping filter: 'hiddenHttpMethodFilter' to: [/*] 
    o.s.b.c.e.FilterRegistrationBean - Mapping filter: 'applicationContextIdFilter' to: [/*] 
    o.s.b.c.e.FilterRegistrationBean - Mapping filter: 'webRequestLoggingFilter' to: [/*] 
    

    The redirect to Google works fine and I get the callback to the filter and the authentication is successful. However after that, the request results in a redirect and it invokes the filter again (the request is the same, I have checked the hasCode). On the second call the authentication in the SecurityContext is null. As part of the first authentication call the Authentication object was populated in the security context, so why does it disappear? I am working with Spring Security for the first time so may have made newbie mistake.

    解决方案

    After playing around with Spring Security configuration and the filters I was finally able to get this working. I had to make couple of important changes

    • I used a standard Spring OAuth2 filter (org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter) instead of the custom filter I was using.
    • Change the intercept URL of the authentication filter to be /googleLogin and added an authentication entry point which redirects to this URL on authentication failure.

    Overall the flow is as follows

    • Browser accesses / and the request passes through the OAuth2ClientContextFilter and OAuth2ClientAuthenticationProcessingFilter as the context does not match. The configured context path for login is /googleLogin
    • The security interceptor FilterSecurityInterceptor detects that the the user is anonymous and throws an access denied exception.
    • Spring security's ExceptionTranslationFilter catches the access denied exception and asks the configured authentication entry point to handle it which issues a redirect to /googleLogin.
    • For the request /googleLogin, the filter OAuth2AuthenticationProcessingFilter tries to access the Google protected resource and an UserRedirectRequiredException is thrown which is translated into a HTTP redirect to Google (with the OAuth2 details) by OAuth2ClientContextFilter.
    • On successful authentication from Google the browser is redirected back to /googleLogin with the OAuth code. The filter OAuth2AuthenticationProcessingFilter handles this and creates an Authentication object and updates the SecurityContext.
    • At this point the user is fully authenticated and redirect to / is issued by the OAuth2AuthenticationProcessingFilter.
    • FilterSecurityInterceptor allows the request to proceed as the SecurityContext contains an Authentication object which is authenticated.
    • Finally the application page which is secured using an expression like isFullyAuthenticated() or similar is rendered.

    The security context xml is as follows:

    <sec:http use-expressions="true" entry-point-ref="clientAuthenticationEntryPoint">
        <sec:http-basic/>
        <sec:logout/>
        <sec:anonymous enabled="false"/>
    
        <sec:intercept-url pattern="/**" access="isFullyAuthenticated()"/>
    
        <!-- This is the crucial part and the wiring is very important -->
        <!-- 
            The order in which these filters execute are very important. oauth2ClientContextFilter must be invoked before 
            oAuth2AuthenticationProcessingFilter, that's because when a redirect to Google is required, oAuth2AuthenticationProcessingFilter 
            throws a UserRedirectException which the oauth2ClientContextFilter handles and generates a redirect request to Google.
            Subsequently the response from Google is handled by the oAuth2AuthenticationProcessingFilter to populate the 
            Authentication object and stored in the SecurityContext
        -->
        <sec:custom-filter ref="oauth2ClientContextFilter" after="EXCEPTION_TRANSLATION_FILTER"/>
        <sec:custom-filter ref="oAuth2AuthenticationProcessingFilter" before="FILTER_SECURITY_INTERCEPTOR"/>
    </sec:http>
    
    <b:bean id="oAuth2AuthenticationProcessingFilter" class="org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter">
        <b:constructor-arg name="defaultFilterProcessesUrl" value="/googleLogin"/>
        <b:property name="restTemplate" ref="googleRestTemplate"/>
        <b:property name="tokenServices" ref="tokenServices"/>
    </b:bean>
    
    <!--
        These token classes are mostly a clone of the Spring classes but have the structure modified so that the response
        from Google can be handled.
    -->
    <b:bean id="tokenServices" class="com.rst.oauth2.google.security.GoogleTokenServices">
        <b:property name="checkTokenEndpointUrl" value="https://www.googleapis.com/oauth2/v1/tokeninfo"/>
        <b:property name="clientId" value="${google.client.id}"/>
        <b:property name="clientSecret" value="${google.client.secret}"/>
        <b:property name="accessTokenConverter">
            <b:bean class="com.rst.oauth2.google.security.GoogleAccessTokenConverter">
                <b:property name="userTokenConverter">
                    <b:bean class="com.rst.oauth2.google.security.DefaultUserAuthenticationConverter"/>
                </b:property>
            </b:bean>
        </b:property>
    </b:bean>
    
    <!-- 
        This authentication entry point is used for all the unauthenticated or unauthorised sessions to be directed to the 
        /googleLogin URL which is then intercepted by the oAuth2AuthenticationProcessingFilter to trigger authentication from 
        Google.
    -->
    <b:bean id="clientAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
        <b:property name="loginFormUrl" value="/googleLogin"/>
    </b:bean>
    

    Also the Java Config for the OAuth2 resources is as follows:

    @Configuration
    @EnableOAuth2Client
    class OAuth2SecurityConfiguration {
        @Autowired
        private Environment env;
    
        @Resource
        @Qualifier("accessTokenRequest")
        private AccessTokenRequest accessTokenRequest;
    
        @Bean
        @Scope("session")
        public OAuth2ProtectedResourceDetails googleResource() {
            AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
            details.setId("google-oauth-client");
            details.setClientId(env.getProperty("google.client.id"));
            details.setClientSecret(env.getProperty("google.client.secret"));
            details.setAccessTokenUri(env.getProperty("google.accessTokenUri"));
            details.setUserAuthorizationUri(env.getProperty("google.userAuthorizationUri"));
            details.setTokenName(env.getProperty("google.authorization.code"));
            String commaSeparatedScopes = env.getProperty("google.auth.scope");
            details.setScope(parseScopes(commaSeparatedScopes));
            details.setPreEstablishedRedirectUri(env.getProperty("google.preestablished.redirect.url"));
            details.setUseCurrentUri(false);
            details.setAuthenticationScheme(AuthenticationScheme.query);
            details.setClientAuthenticationScheme(AuthenticationScheme.form);
            return details;
        }
    
        private List<String> parseScopes(String commaSeparatedScopes) {
            List<String> scopes = newArrayList();
            Collections.addAll(scopes, commaSeparatedScopes.split(","));
            return scopes;
        }
    
        @Bean
        @Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
        public OAuth2RestTemplate googleRestTemplate() {
            return new OAuth2RestTemplate(googleResource(), new DefaultOAuth2ClientContext(accessTokenRequest));
        }
    }
    

    I had to override some of the Spring classes as the format of the token from Google and the one expected by Spring don't match. So there is some custom handiwork required there.

    这篇关于春季安全OAuth2(谷歌)网络应用程序在重定向循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆