2

我很想用Spring Security配置Spring Boot應用程序來支持兩種登錄機制:表單登錄和Google OAuth2登錄。如何配置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

這是我如何解決它使用兩個WebSecurityConfigurerAdapter S:

@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