Maison  >  Article  >  Java  >  Comment Spring Boot intègre-t-il JWT pour réaliser l'authentification front-end et back-end ?

Comment Spring Boot intègre-t-il JWT pour réaliser l'authentification front-end et back-end ?

WBOY
WBOYavant
2023-05-18 13:19:061435parcourir

Introduction à JWT

JWT (nom complet : Json Web Token) est une norme ouverte (RFC 7519) qui définit une manière compacte et autonome de transmettre en toute sécurité des informations entre les parties en tant qu'objet JSON.

Pourquoi utiliser JWT

Quels sont les inconvénients de l'authentification de session traditionnelle ?

  • Les informations de connexion de chaque utilisateur seront enregistrées dans la session du serveur. À mesure que le nombre d'utilisateurs augmente, la surcharge du serveur augmentera considérablement.

  • Les informations de session sont stockées dans la mémoire du serveur, ce qui entraînera une panne des applications distribuées. Bien que les informations de session puissent être stockées uniformément dans le cache Redis, cela peut augmenter la complexité.

  • L'authentification de session étant basée sur Cookie, elle n'est pas applicable aux terminaux non-navigateurs et mobiles.

  • Le système de séparation front-end et back-end, car le front-end et le back-end sont inter-domaines et les informations des cookies ne peuvent pas être croisées, donc l'authentification de session ne peut pas continuer l'authentification inter-domaine.

Avantages de l'authentification JWT

  • Simple : le volume de données du jeton JWT est faible et la vitesse de transmission est également très rapide.

  • Multilingue : le jeton JWT est stocké sur le client sous forme cryptée JSON, donc JWT est multilingue et pris en charge par n'importe quel formulaire Web. Multiplateforme : ne repose pas sur les cookies et les sessions, et n'a pas besoin de stocker les informations de session sur le serveur. Il est très adapté aux applications distribuées et peut être utilisé pour l'expansion.

Structure des données de JWT

Comment Spring Boot intègre-t-il JWT pour réaliser lauthentification front-end et back-end ?

En-tête

La première partie de JWT est la partie d'en-tête, qui est un objet Json décrivant les métadonnées JWT, généralement comme indiqué ci-dessous.

{
    "alg": "HS256",
    "typ": "JWT"
}

L'attribut alg indique l'algorithme utilisé pour la signature, la valeur par défaut est HMAC SHA256 (écrit HS256), l'attribut typ indique le type de jeton et les jetons JWT sont uniformément écrits comme JWT.

Payload

La deuxième partie de JWT est Payload, qui est également un objet Json. En plus de contenir les données qui doivent être transmises, vous avez le choix entre sept champs par défaut. iss : émetteur exp : heure d'expiration sub : sujet aud : utilisateur nbf : non disponible avant iat : heure de sortie jti : l'ID JWT est utilisé pour identifier ce JWT

{
    //默认字段
    "sub":"主题123",
    //自定义字段
    "name":"java",
    "isAdmin":"true",
    "loginTime":"2021-12-05 12:00:03"
}

Il est important de noter que JWT n'est pas chiffré par défaut, n'importe qui peut déchiffrer son contenu, donc si certaines informations sensibles ne sont pas stockées ici, pour éviter les fuites d'informations. Les objets JSON sont également convertis en chaînes à l'aide de l'algorithme d'URL Base64 et enregistrés.

Signature

La partie hachage de signature consiste à signer les deux parties de données ci-dessus. Elle doit utiliser des données d'en-tête et de charge utile codées en base64, et générer un hachage via l'algorithme spécifié pour garantir que les données ne seront pas falsifiées.

Spring Boot intègre JWT

Présentation du package Jwt

<dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
  </dependency>

Écriture de la classe d'outils jwt

public class JwtUtil
{
//创建jwt
public static String createJWT(String subject, String issue, Object claim,
            long ttlMillis)
    {
       //当前时间
        long nowMillis = System.currentTimeMillis();
        //过期时间
        long expireMillis = nowMillis + ttlMillis;
        String result = Jwts.builder()
                .setSubject(subject) //设置主题
                .setIssuer(issue) //发行者
                .setId(issue)//jwtID
                .setExpiration(new Date(expireMillis)) //设置过期日期
                .claim("user", claim)//主题,可以包含用户信息
                .signWith(getSignatureAlgorithm(), getSignedKey())//加密算法
                .compressWith(CompressionCodecs.DEFLATE).compact();//对载荷进行压缩

        return result;
    }
    
    // 解析jwt
    public static Jws<Claims> pareseJWT(String jwt)
    {
        Jws<Claims> claims;
        try
        {
            claims = Jwts.parser().setSigningKey(getSignedKey())
                    .parseClaimsJws(jwt);
        }
        catch (Exception ex)
        {
            claims = null;
        }
        return claims;
    }

   //获取主题信息
    public static Claims getClaims(String jwt)
    {
        Claims claims;
        try
        {
            claims = Jwts.parser().setSigningKey(getSignedKey())
                    .parseClaimsJws(jwt).getBody();
        }
        catch (Exception ex)
        {
            claims = null;
        }
        return claims;
    }
  }
  
   /**
     * 获取密钥
     * 
     * @return Key
     */
    private static Key getSignedKey()
    {
        byte[] apiKeySecretBytes = DatatypeConverter
                .parseBase64Binary(getAuthKey());
        Key signingKey = new SecretKeySpec(apiKeySecretBytes,
                getSignatureAlgorithm().getJcaName());
        return signingKey;
    }
    
    private static SignatureAlgorithm getSignatureAlgorithm()
    {
        return SignatureAlgorithm.HS256;
    }
  
  //获取密钥,可以动态配置
  public static String getAuthKey()
  {
        String auth = "123@#1234";
  }

Intercepteur d'authentification de jeton

 Component
public class TokenInterceptor extends HandlerInterceptorAdapter
{
    public static Log logger = LogManager.getLogger(TokenInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception
    {
        String uri = request.getRequestURI();
        logger.info("start TokenInterceptor preHandle.." + uri);
         
		//需要过滤特殊请求
        if (SystemUtil.isFree(uri) || SystemUtil.isProtected(uri))
        {
            return true;
        }
        
		
        String metohd=request.getMethod().toString();
        logger.info("TokenInterceptor request method:"+metohd);
        //options 方法需要过滤
        if("OPTIONS".equals(metohd))
        {
            return true;   
        }
        
		//是否开启token认证
        boolean flag = SystemUtil.getVerifyToken();
        ResponseResult result = new ResponseResult();
		//从请求的head信息中获取token
        String token = request.getHeader("X-Token");

        if (flag)
        {
            if(StringUtils.isEmpty(token))
            {
                token=request.getParameter("X-Token");    
            }
            // token不存在
            if (StringUtils.isEmpty(token))
            {
                result.setCode(ResultCode.NEED_AUTH.getCode());
                result.setMsg(ResultCode.NEED_AUTH.getMsg());
                WebUtil.writeJson(result, response);
                return false;
            }
            else
            {
                Claims claims = JwtUtil.getClaims(token);
                String subject = "";
                if (claims != null)
                {
                    subject = claims.getSubject();
                    // 验证主题
                    if (StringUtils.isEmpty(subject))
                    {
                        result.setCode(ResultCode.INVALID_TOKEN.getCode());
                        result.setMsg(ResultCode.INVALID_TOKEN.getMsg());
                        WebUtil.writeJson(result, response);
                        return false;
                    }								
                }
                else
                {
                    result.setCode(ResultCode.INVALID_TOKEN.getCode());
                    result.setMsg(ResultCode.INVALID_TOKEN.getMsg());
                    WebUtil.writeJson(result, response);
                    return false;
                }
            }
        }
        return true;
    }

}

Intercepteur de configuration

@Configuration
public class WebConfig implements WebMvcConfigurer
{
    @Resource
    private TokenInterceptor tokenInterceptor;

    public void addInterceptors(InterceptorRegistry registry)
    {
        registry.addInterceptor(tokenInterceptor).addPathPatterns("/**");
    }
 }

Processus de vérification de connexion

Comment Spring Boot intègre-t-il JWT pour réaliser lauthentification front-end et back-end ?

Exemple de code

@RequestMapping("login")
public Result login(HttpServletResponse response)
{
    Map<String, Object> map = new HashMap<>();
    //
    Result result = loginAuth(user);
    int code = result.getCode();
            //登录认证成功
    if (code ==ResultCode.SUCCESS)
    {
        //默认为7天
        Long ttlMillis = 7*1000 * 60 * 60 * 24;
        //过期时间
        long expreTime = System.currentTimeMillis() + ttlMillis;
        String tokenKey = UUID.randomUUID().toString();
        String tokenId = JwtUtil.createJWT(user.getUserId(), tokenKey,
                user.getPassword(), expreTime);                   
        map.put("expreTime", expreTime);				
        map.put("tokenId", tokenId);           
    }
    else
    {
        logger.error("login error:" +FastJsonUtil.toJSONString(result));
    }
    return result;
}

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer