Vérifiez le jeton d'ID obtenu de Firebase côté serveur (Java + SpringBoot)

introduction

Vous pouvez obtenir un jeton d'identification (JWT) lorsque vous vous connectez à l'aide de l'authentification Firebase. Par exemple, lors de l'authentification de connexion avec SPA, vous souhaiterez peut-être vous connecter à l'aide de Firebase avec un client (JavaScript), envoyer le jeton acquis au serveur et associer l'uid dans JWT à l'utilisateur géré par l'application. Je pense que oui.

スクリーンショット 2019-02-19 14.53.20.png

Cette fois, j'écrirai principalement la méthode de vérification de JWT côté serveur (java + SpringBoot).

Implémentation client

Cette fois, j'utiliserai Nuxt. Comment obtenir et envoyer des jetons.

Processus d'authentification (extrait)


async signin() {
  try {
    //Authentifiez-vous à l'aide de l'adresse e-mail et du mot de passe
    await firebase.auth().signInWithEmailAndPassword(this.email, this.password)

    //Obtenir un jeton d'identification (JWT)
    const token = await firebase.auth().currentUser.getIdToken(true)

    //Enregistrer dans le stockage local
    localStorage.setItem('token', token)

    //Transition vers la page après authentification
    this.$router.push('/')
  } catch (e) {
    //Au moment d'une erreur d'authentification ou d'une erreur d'acquisition de jeton
    console.log(e)
  }
}

~/plugins/axios.js


export default function ({ $axios }) {
  $axios.onRequest(config => {
    const token = localStorage.getItem('token');
    if (token) {
      //S'il y a un jeton dans le stockage local, donnez-le à l'en-tête de la demande (autorisation)
      config.headers.common['Authorization'] = "Bearer " + token;
    }
  })
}

Implémentation côté serveur

Utilisez OnecePerRequestFilter de Spring Security.

De plus, les bibliothèques suivantes sont utilisées.

Nom de la bibliothèque Utilisation
OkHttp Client HTTP
jjwt Vérification JWT

LoginFilter.java


@Component
public class LoginFilter extends OncePerRequestFilter {

  //Enregistrez ObjectMapper en tant que bean à l'avance.
  @Autowired
  ObjectMapper objectMapper;

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
      FilterChain filterChain) throws ServletException, IOException {

    //Définir les informations de connexion de l'utilisateur en contexte
    SecurityContextHolder.getContext().setAuthentication(new PreAuthenticatedAuthenticationToken(
        auth(request), null));

    filterChain.doFilter(request, response);
  }

  //Obtenir les informations de connexion de l'utilisateur
  private LoginUser auth(HttpServletRequest request) {
    
    //Extraire JWT de l'en-tête de la demande
    String token = getToken(request);

    try {

      //Vérifiez JWT, obtenez des réclamations
      //Si la validation échoue, une exception est levée.
      Jws<Claims> claim = Jwts.parser()
          .setSigningKeyResolver(new GoogleSigningKeyResolver()) //Besoin de votre propre résolveur
          .parseClaimsJws(token);

      //Obtenez l'ID de la partie du corps de la réclamation
      String uid = (String)claim.getBody().get("user_id");

      //Obtenez uid et recherchez des informations sur les utilisateurs
      User user = userService.findByUid(uid);

      if(user == null){
        throw new BadCredentialsException("L'utilisateur n'existe pas");
      }

      return new LoginUser(user);

    } catch (Exception e) {
      throw new BadCredentialsException("Jeton invalide");
    }
  }

  //Obtenez le jeton de l'en-tête de la demande.
  private String getToken(HttpServletRequest request) {
    String token = request.getHeader("Authorization");
    if (token == null || !token.startsWith("Bearer ")) {
      return null;
    }
    return token.substring("Bearer ".length());
  }

  /**
   *Nous vous retournerons la clé publique utilisée pour la signature.
   * 
   * @author h.ono
   *
   */
  public class GoogleSigningKeyResolver extends SigningKeyResolverAdapter {

    @Override
    public Key resolveSigningKey(JwsHeader jwsHeader, Claims claims) {

      try {
        Map<String, Object> map = getJwks();

        if (map.isEmpty()) {
          return null;
        }

        String keyValue = (String) map.get(jwsHeader.getKeyId());

        if (keyValue == null) {
          return null;
        }
        //Point important
        //Supprimez les étiquettes de début (BEGIN) et de fin (END).
        keyValue = keyValue
            .replaceAll("-----BEGIN CERTIFICATE-----\n", "")
            .replaceAll("-----END CERTIFICATE-----\n", "");

        InputStream in = new ByteArrayInputStream(Base64.decodeBase64(keyValue.getBytes("UTF-8")));
        X509Certificate certificate = (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(in);
        return certificate.getPublicKey();

      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }

    /**
     *Obtenez JWKS de Google.
     * 
     * @return JWKS
     */
    private Map<String, Object> getJwks() {
      OkHttpClient client = new OkHttpClient();
      Request request = new Request.Builder()
          .url("https://www.googleapis.com/robot/v1/metadata/x509/[email protected]")
          .build();
      try (Response response = client.newCall(request).execute()) {
        return objectMapper.readValue(response.body().string(), new TypeReference<Map<String, Object>>() {
        });
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }
  }

}

en conclusion

J'ai pu associer l'UID obtenu de Firebase à l'utilisateur qui possède l'application. J'ai fait beaucoup de recherches, mais la plupart de l'authentification a été effectuée côté client, j'ai donc eu du mal à arriver à une méthode comme celle-ci. .. ..

Lors de la vérification de JWT, j'ai également essayé java-jwt fourni par auth0, mais lors de l'obtention de la clé publique, Je n'ai pas pu l'obtenir car il ne prend pas en charge le format X.509.

Site de référence

Recommended Posts

Vérifiez le jeton d'ID obtenu de Firebase côté serveur (Java + SpringBoot)
Kick ShellScript sur le serveur depuis Java
[Java] Comment récupérer les paramètres passés du html côté serveur
Migrer de Java vers Kotlin côté serveur + Spring-boot
Utilisation de la base de données (SQL Server 2014) à partir d'un programme Java 04/01/2018
JSON en Java et Jackson Partie 1 Renvoyer JSON à partir du serveur
Apache Geode-Easy moyen d'exécuter la logique côté serveur
Comment désactiver Set-Cookie de l'API sur la face avant
Installez le plugin memcached sur MySQL et accédez à partir de Java