[JAVA] J'ai essayé Google Sign-In avec Spring Boot + Spring Security REST API

J'ai rendu possible la connexion au serveur API REST créé avec Spring Boot avec Google Sign-In, donc je vais écrire ce que j'ai fait.

La version de Spring Boot que j'utilise est 1.5.7. La plupart de ce que vous faites ci-dessous peut être possible avec @ EnableOAuth2Sso, mais ce n'est pas intéressant, ou c'est tout.

Préparation (API REST pour l'authentification)

Avant de prendre en charge la connexion à Google, modifiez le comportement par défaut de Spring Security en une ambiance REST.

Site de référence: http://www.baeldung.com/securing-a-restful-web-service-with-spring-security

Point d'accès

Dans une application Web standard, si vous accédez à une ressource sécurisée dans un état non authentifié, il vous demandera automatiquement de vous authentifier, mais comme le service REST s'authentifie explicitement, dans ce cas, appuyez simplement sur 401 Il sera retourné.

RestAuthenticationEntryPoint.java


@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {

  @Override
  public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
    response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
  }
}

Renvoie «200» au lieu de «301» lors d'une connexion réussie

Par défaut, lorsque la connexion est réussie, «301» est renvoyé et l'écran est guidé vers l'écran après la connexion, mais dans REST, «200» est simplement renvoyé. Créez un ʻAuthenticationSuccessHandler qui ne redirige pas en se référant au SavedRequestAwareAuthenticationSuccessHandler`.

RestSavedRequestAwareAuthenticationSuccessHandler.java


@Component
public class RestSavedRequestAwareAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

  private RequestCache requestCache = new HttpSessionRequestCache();

  @Override
  public void onAuthenticationSuccess(HttpServletRequest request,
                                      HttpServletResponse response, Authentication authentication) {
    SavedRequest savedRequest = requestCache.getRequest(request, response);

    if (savedRequest == null) {
      clearAuthenticationAttributes(request);
      return;
    }
    String targetUrlParameter = getTargetUrlParameter();
    if (isAlwaysUseDefaultTargetUrl()
      || (targetUrlParameter != null && StringUtils.hasText(request
      .getParameter(targetUrlParameter)))) {
      requestCache.removeRequest(request, response);
      clearAuthenticationAttributes(request);
      return;
    }

    clearAuthenticationAttributes(request);
  }
}

Renvoie «401» au lieu de «302» en cas d'échec de la connexion

De même, si la connexion échoue, renvoyez simplement «401». Vous pouvez utiliser SimpleUrlAuthenticationFailureHandler de Spring tel quel.

Renvoyez simplement «200» lors de la déconnexion

De même, lors de la déconnexion, il ne redirige pas et ne renvoie que «200». Vous pouvez également utiliser SimpleUrlLogoutSuccessHandler de Spring ici.

SecurityConfig Créez une configuration dans l'état jusqu'à présent.

SecurityConfig.java


@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private RestAuthenticationEntryPoint authenticationEntryPoint;

  @Autowired
  private RestSavedRequestAwareAuthenticationSuccessHandler authenticationSuccessHandler;

  @Autowired
  private SimpleUrlAuthenticationFailureHandler authenticationFailureHandler;

  @Autowired
  private SimpleUrlLogoutSuccessHandler logoutSuccessHandler;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .csrf().disable()
      .authorizeRequests()
        .antMatchers("/api/**").authenticated()
        .and()
      .exceptionHandling()
        .authenticationEntryPoint(authenticationEntryPoint)
        .and()
      .formLogin()
        .successHandler(authenticationSuccessHandler)
        .failureHandler(authenticationFailureHandler)
        .and()
      .logout()
        .logoutSuccessHandler(logoutSuccessHandler)
    ;
  }

  @Bean
  public SimpleUrlAuthenticationFailureHandler simpleUrlAuthenticationFailureHandler() {
    return new SimpleUrlAuthenticationFailureHandler();
  }

  @Bean
  public SimpleUrlLogoutSuccessHandler simpleUrlLogoutSuccessHandler() {
    return new SimpleUrlLogoutSuccessHandler();
  }
}

Mettre en œuvre la connexion à Google

Enfin le sujet principal. Coco et Coco -auth) comme référence. Depuis l'application Web (face avant), ʻid_token qui peut être obtenu lors de la connexion est implémenté dans POST vers / loginavecx-www-form-urlencoded`. Le nom du paramètre est «google_id_token».

Correction de SecurityConfig

Intégrez formLogin () au SecurityConfig # configure (HttpSecurity http) créé comme suit.

SecurityConfig.java


      .formLogin()
        .passwordParameter("google_id_token")
        .successHandler(authenticationSuccessHandler)

Je viens d'ajouter passwordParameter (" google_id_token "). Vous recevrez maintenant ʻid_token` comme mot de passe pour l'authentification avec votre nom d'utilisateur et votre mot de passe par défaut.

Implémentation de ʻAuthenticationProvider`

Maintenant que vous avez reçu ʻid_token`, il ne vous reste plus qu'à implémenter l'authentification.

GoogleIdAuthenticationProvider.java


@Component
public class GoogleIdAuthenticationProvider implements AuthenticationProvider {

  private final String clientId = "XXX.apps.googleusercontent.com";

  @Override
  public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    String tokenString = (String) authentication.getCredentials();
    GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(UrlFetchTransport.getDefaultInstance(), JacksonFactory.getDefaultInstance())
      .setAudience(singletonList(clientId))
      .build();
    GoogleIdToken idToken;
    try {
      idToken = verifier.verify(tokenString);
      if (idToken == null) {
        throw new BadCredentialsException("Failed to verify token");
      }
    } catch (GeneralSecurityException|IOException e) {
      throw new AuthenticationServiceException("Failed to verify token", e);
    }

    GoogleIdToken.Payload payload = idToken.getPayload();
    String userId = payload.getSubject();
    String name = (String) payload.get("name");
    GoogleUser user = new GoogleUser(userId, name);
    List<GrantedAuthority> authorities = singletonList(new SimpleGrantedAuthority("ROLE_USER"));
    return new UsernamePasswordAuthenticationToken(user, tokenString, authorities);
  }

  @Override
  public boolean supports(Class<?> authentication) {
    return UsernamePasswordAuthenticationToken.class.equals(authentication);
  }
}

Si vous voulez vous limiter à un domaine spécifique, vous pouvez le faire en cochant payload.getHostedDomain ().

La classe «GoogleUser» est la suivante.

GoogleUser.java


@Data
@RequiredArgsConstructor
@AllArgsConstructor
public class GoogleUser implements UserDetails {

  @NotNull
  @Setter(AccessLevel.NONE)
  private String userId;

  private String username;

  @Override
  public Collection<? extends GrantedAuthority> getAuthorities() {
    return null;
  }

  @Override
  public String getPassword() {
    return null;
  }

  @Override
  public boolean isAccountNonExpired() {
    return false;
  }

  @Override
  public boolean isAccountNonLocked() {
    return false;
  }

  @Override
  public boolean isCredentialsNonExpired() {
    return false;
  }

  @Override
  public boolean isEnabled() {
    return false;
  }
}

Vous êtes maintenant prêt pour la connexion à Google.

Recommended Posts

J'ai essayé Google Sign-In avec Spring Boot + Spring Security REST API
J'ai essayé "License OCR" avec l'API Google Vision
J'ai essayé "Receipt OCR" avec l'API Google Vision
J'ai essayé d'utiliser l'API Google Cloud Vision
J'ai essayé Java8 + Spring Boot avec GAE SE (et à propos de son environnement de développement)
J'ai essayé APN (notification à distance) à l'aide de l'API REST Parse.com
J'ai essayé de découvrir notre obscurité avec l'API Chatwork
J'ai essayé de frapper l'API avec le client python d'echonest
J'ai essayé de gratter avec Python
Hello World avec Google App Engine (Java 8) + Spring Boot + Gradle
J'ai essayé le clustering avec PyCaret
J'ai essayé de connecter Raspeye et conect + avec l'API Web
J'ai essayé la gestion du suivi avec l'API Twitter et Python (facile)
J'ai essayé de sauvegarder l'historique des demandes d'API DRF avec django-request
J'ai essayé l'API Google Cloud Vision pour la première fois
J'ai essayé gRPC avec Python
J'ai essayé de gratter avec du python
Hello World avec Google App Engine (Java 11) + Spring Boot + Gradle
J'ai essayé d'utiliser l'API Google avec Ruby et Python - Faites de la base de données une feuille de calcul et gérez-la avec Google Drive
J'ai essayé d'automatiser tout, y compris l'authentification en deux étapes de Google OAuth
J'ai essayé ChatOps avec Slack x API Gateway x Lambda (Python) x RDS
J'ai essayé d'utiliser l'API de reconnaissance vocale docomo et l'API Google Speech en Java
Utilisez Nutanix avec l'API REST, partie 2
J'ai essayé de créer l'API Quip
J'ai essayé le roman Naro API 2
J'ai essayé l'apprentissage automatique avec liblinear
J'ai essayé webScraping avec python.
J'ai essayé de déplacer de la nourriture avec SinGAN
J'ai essayé d'implémenter DeepPose avec PyTorch
J'ai touché l'API de Tesla
J'ai essayé la détection de visage avec MTCNN
J'ai essayé l'API du roman Naruro
J'ai essayé d'exécuter prolog avec python 3.8.2.
J'ai essayé la communication SMTP avec Python
J'ai essayé la génération de phrases avec GPT-2
J'ai essayé d'apprendre LightGBM avec Yellowbrick
Présentation de l'API Google Map avec rails
J'ai essayé la reconnaissance faciale avec OpenCV
J'ai essayé d'utiliser l'API checkio
J'ai essayé de supprimer régulièrement les mauvais tweets avec l'API AWS Lambda + Twitter
J'ai essayé d'extraire des caractères des sous-titres (OpenCV: API Google Cloud Vision)
J'ai essayé de créer un LINE BOT "Sakurai-san" avec API Gateway + Lambda
J'ai essayé d'obtenir le code d'authentification de l'API Qiita avec Python.
J'ai essayé d'obtenir les informations sur le film de l'API TMDb avec Python
J'ai essayé de frapper l'API Mastodon avec Ruby (Faraday) / Python (Pycurl) / PHP (Curl)
J'ai essayé de mettre à jour le calendrier Google avec des rendez-vous CSV à l'aide de Python et de l'API Google
J'ai essayé l'analyse de régression multiple avec régression polypoly
J'ai essayé d'envoyer un SMS avec Twilio
J'ai essayé d'utiliser Amazon SQS avec django-celery
Reconnaissance vocale en streaming avec l'API Google Cloud Speech
J'ai essayé d'implémenter Autoencoder avec TensorFlow
J'ai essayé linebot avec flacon (anaconda) + heroku
J'ai essayé de visualiser AutoEncoder avec TensorFlow
J'ai essayé de commencer avec Hy
J'ai essayé d'utiliser l'API de données YOUTUBE V3
J'ai essayé d'utiliser du sélénium avec du chrome sans tête
J'ai essayé l'analyse factorielle avec des données Titanic!