首页 文章

如何配置Spring Boot和Spring Security以支持表单登录和Google OAuth2登录

提问于
浏览
2

我正准备使用Spring Security配置Spring Boot应用程序以支持两种登录机制:表单登录和Google OAuth2登录 .

我想要一个带有传统登录表单的登录页面 . 此页面还会显示“使用Google按钮验证” .

登录表单将是默认登录方法,也就是说,当尝试访问受保护资源时,login.jsp将呈现 . 在这里,用户可以单击oauth按钮 .

关键是我可以单独配置它们,无论是登录还是Google身份验证,但我无法让它们协同工作 .

1.-表格登录:

@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter{

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .anyRequest().authenticated()
        .and()
            .formLogin()

2.-谷歌授权:

@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter{

    private final String LOGIN_URL = "/login"

    @Autowired
    OAuth2ClientContextFilter oAuth2ClientContextFilter

    @Bean
    public AuthenticationEntryPoint authenticationEntryPoint() {
        return new LoginUrlAuthenticationEntryPoint(LOGIN_URL)
    }

    @Bean
    public OpenIDConnectAuthenticationFilter openIdConnectAuthenticationFilter(){
        return new OpenIDConnectAuthenticationFilter(LOGIN_URL)
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterAfter(oAuth2ClientContextFilter, AbstractPreAuthenticatedProcessingFilter.class)
            .addFilterAfter(openIdConnectAuthenticationFilter(), OAuth2ClientContextFilter.class)
            .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())
        .and()
            .authorizeRequests()
                .anyRequest.authenticated()
    }
}


class OpenIDConnectAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    @Resource
    private OAuth2RestOperations restTemplate

    protected OpenIDConnectAuthenticationFilter(String defaultFilterProcessesUrl) {
        super(defaultFilterProcessesUrl)
        setAuthenticationManager({authentication -> authentication}) // AbstractAuthenticationProcessingFilter requires an authentication manager.
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException, IOException, ServletException {
        final ResponseEntity<UserInfo> userInfoResponseEntity = restTemplate.getForEntity("https://www.googleapis.com/oauth2/v2/userinfo", UserInfo.class)
        new PreAuthenticatedAuthenticationToken(userInfoResponseEntity.getBody(), empty(), NO_AUTHORITIES)
    }
}

class UserInfo {
    final String id
    final String name
    final String givenName
    final String familyName
    final String gender
    final String picture
    final String link

    @JsonCreator
    public UserInfo(@JsonProperty("id") String id,
                    @JsonProperty("name") String name,
                    @JsonProperty("given_name") String givenName,
                    @JsonProperty("family_name") String familyName,
                    @JsonProperty("gender") String gender,
                    @JsonProperty("picture") String picture,
                    @JsonProperty("link") String link) {
        this.id = id
        this.name = name
        this.givenName = givenName
        this.familyName = familyName
        this.gender = gender
        this.picture = picture
        this.link = link
    }

}

@Configuration
@EnableOAuth2Client
class OAuth2Client {

    @Value('${google.oauth2.clientId}')
    private String clientId

    @Value('${google.oauth2.clientSecret}')
    private String clientSecret

    @Bean
    // TODO retrieve from https://accounts.google.com/.well-known/openid-configuration ?
    public OAuth2ProtectedResourceDetails googleOAuth2Details() {
        AuthorizationCodeResourceDetails googleOAuth2Details = new AuthorizationCodeResourceDetails()
        googleOAuth2Details.setAuthenticationScheme(form)
        googleOAuth2Details.setClientAuthenticationScheme(form)
        googleOAuth2Details.setClientId(clientId)
        googleOAuth2Details.setClientSecret(clientSecret)
        googleOAuth2Details.setUserAuthorizationUri("https://accounts.google.com/o/oauth2/auth")
        googleOAuth2Details.setAccessTokenUri("https://www.googleapis.com/oauth2/v3/token")
        googleOAuth2Details.setScope(asList("openid"))
        googleOAuth2Details
    }

    @Resource
    private OAuth2ClientContext oAuth2ClientContext

    @Bean
    @Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
    public OAuth2RestOperations googleOAuth2RestTemplate() {
        new OAuth2RestTemplate(googleOAuth2Details(), oAuth2ClientContext)
    }
}

class CustomUserDetailsService implements AuthenticationUserDetailsService<OpenIDAuthenticationToken> {

    UserDetails loadUserDetails(OpenIDAuthenticationToken token) throws UsernameNotFoundException {
        new User(token.name, "", AuthorityUtils.createAuthorityList("ROLE_USER"))
    }
}

1 回答

  • 2

    这就是我用两个 WebSecurityConfigurerAdapter 解决它的方法:

    @EnableWebSecurity
    class SecurityConfig extends WebSecurityConfigurerAdapter{
    
        @Configuration
        @Order(1)
        static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
    
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http
                    .antMatcher("/secure-home")
                    .authorizeRequests()
                        .anyRequest().authenticated()
                        .and()
                    .formLogin()
                        .loginPage("/login")
                        .permitAll()
            }
        }
    
        @Configuration
        @Order(2)
        static class OAuth2SecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
    
            private final String LOGIN_URL = "/googleLogin";
    
            @Autowired
            OAuth2ClientContextFilter oAuth2ClientContextFilter
    
            @Bean
            AuthenticationEntryPoint authenticationEntryPoint() {
                new LoginUrlAuthenticationEntryPoint(LOGIN_URL)
            }
    
            @Bean
            OpenIDConnectAuthenticationFilter openIdConnectAuthenticationFilter() {
                new OpenIDConnectAuthenticationFilter(LOGIN_URL)
            }
    
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http
                    .addFilterAfter(oAuth2ClientContextFilter, AbstractPreAuthenticatedProcessingFilter.class)
                    .addFilterAfter(openIdConnectAuthenticationFilter(), OAuth2ClientContextFilter.class)
                .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())
                .and()
                    .authorizeRequests()
                        .antMatchers(GET, "/googleOAuth2").authenticated()
            }
        }
    }
    

    完整的源代码可在此处获取:https://github.com/codependent/spring-boot-google-signin

相关问题