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

5

我在努力将Spring Boot应用程序与Spring Security配合使用,以支持两种登录机制:表单登录和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个回答

3

这是我使用两个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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接