>  기사  >  Java  >  Spring Boot는 프런트엔드 및 백엔드 인증을 달성하기 위해 JWT를 어떻게 통합합니까?

Spring Boot는 프런트엔드 및 백엔드 인증을 달성하기 위해 JWT를 어떻게 통합합니까?

WBOY
WBOY앞으로
2023-05-18 13:19:061436검색

JWT 소개

JWT(전체 이름: Json Web Token)는 당사자 간에 정보를 JSON 개체로 안전하게 전송하는 간결하고 독립적인 방법을 정의하는 개방형 표준(RFC 7519)입니다.

JWT를 사용하는 이유

기존 세션 인증의 단점은 무엇인가요?

  • 각 사용자의 로그인 정보는 서버의 세션에 저장되며, 사용자 수가 늘어날수록 서버 오버헤드가 크게 늘어납니다.

  • 세션 정보는 서버의 메모리에 저장되므로 분산 애플리케이션에 오류가 발생할 수 있습니다. 세션 정보가 Redis 캐시에 균일하게 저장될 수 있지만 이로 인해 복잡성이 증가할 수 있습니다.

  • 세션 인증은 쿠키 기반이므로 비 브라우저 및 모바일 단말에서는 적용되지 않습니다.

  • 프런트엔드와 백엔드 분리 시스템은 프런트엔드와 백엔드가 크로스 도메인이고, 쿠키 정보를 교차할 수 없기 때문에 세션 인증이 크로스 도메인 인증을 이어갈 수 없기 때문입니다.

JWT 인증의 장점

  • 간단함: JWT 토큰의 데이터 양은 적고 전송 속도도 매우 빠릅니다.

  • 교차 언어: JWT 토큰은 JSON 암호화 형식으로 클라이언트에 저장되므로 JWT는 언어 간이며 모든 웹 양식에서 지원됩니다. 크로스 플랫폼: 쿠키와 세션에 의존하지 않으며 서버에 세션 정보를 저장할 필요가 없으며 분산 애플리케이션에 매우 적합하며 확장에 사용할 수 있습니다.

JWT의 데이터 구조

Spring Boot는 프런트엔드 및 백엔드 인증을 달성하기 위해 JWT를 어떻게 통합합니까?

Header

JWT의 첫 번째 부분은 일반적으로 아래와 같이 JWT 메타데이터를 설명하는 Json 객체인 헤더 부분입니다.

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

alg 속성은 서명에 사용되는 알고리즘을 나타내며, 기본값은 HMAC SHA256(HS256으로 작성됨)이고, typ 속성은 토큰 유형을 나타내며, JWT 토큰은 JWT로 일률적으로 작성됩니다.

Payload

JWT의 두 번째 부분은 Json 객체이기도 한 Payload입니다. 전달해야 하는 데이터를 포함하는 것 외에도 선택할 수 있는 7개의 기본 필드가 있습니다. iss: 발행자 exp: 만료 시간 sub: 제목 aud: 사용자 nbf: 이전에는 사용할 수 없음 iat: 릴리스 시간 jti: JWT ID는 이 JWT를 식별하는 데 사용됩니다

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

JWT는 기본적으로 암호화되지 않는다는 점에 유의하는 것이 중요합니다. 내용을 해독하므로 일부 민감한 정보가 여기에 저장되지 않은 경우 정보 유출을 방지할 수 있습니다. JSON 객체도 Base64 URL 알고리즘을 사용하여 문자열로 변환되어 저장됩니다.

Signature

서명 해시 부분은 위 두 부분의 데이터에 서명하는 것으로, base64로 인코딩된 헤더와 페이로드 데이터를 사용해야 하며, 데이터가 변조되지 않도록 지정된 알고리즘을 통해 해시를 생성해야 합니다.

Spring Boot는 JWT를 통합합니다

Jwt 패키지 소개

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

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";
  }

토큰 인증 인터셉터

 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;
    }

}

구성 인터셉터

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

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

로그인 확인 프로세스

Spring Boot는 프런트엔드 및 백엔드 인증을 달성하기 위해 JWT를 어떻게 통합합니까?

샘플 코드

아아아아

위 내용은 Spring Boot는 프런트엔드 및 백엔드 인증을 달성하기 위해 JWT를 어떻게 통합합니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제