J'ai du mal à configurer une application Spring Boot avec Spring Security pour prendre en charge deux mécanismes de connexion: la connexion par formulaire et la connexion Google OAuth2.
Je souhaite avoir une page de connexion avec le formulaire de connexion traditionnel. Cette page aurait également un bouton "Authentifier avec Google".
Le formulaire de connexion serait la méthode de connexion par défaut, c'est-à-dire que lors d'une tentative d'accès à une ressource protégée, le login.jsp serait rendu. Ici, l'utilisateur peut cliquer sur le bouton oauth.
Le fait est que je peux les configurer séparément, que ce soit par connexion par formulaire ou par authentification Google, mais je ne suis pas en mesure de les faire fonctionner ensemble.
1.- Connexion par formulaire:
@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
2.- Authentification Google:
@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"))
}
}
Voici comment je l'ai résolu en utilisant deux 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()
}
}
}
Le code source complet est disponible ici: https://github.com/codependent/spring-boot-google-signin
Cet article est collecté sur Internet, veuillez indiquer la source lors de la réimpression.
En cas d'infraction, veuillez [email protected] Supprimer.
laisse moi dire quelques mots