JWT란 무엇입니까? 이 기사에서는 JWT를 이해하고, 노드에서 JWT를 적용하는 방법과 JWT의 장점과 단점을 소개합니다. 모든 분들께 도움이 되기를 바랍니다.
JWT는 JSON Web Token 의 약어로, 네트워크 애플리케이션 환경의 인증 솔루션입니다. 기존 인증 메커니즘에서는 다음 단계에 지나지 않습니다.
1. 사용자는 계정 비밀번호를 서버로 보냅니다. 2. 서버가 계정 비밀번호를 확인한 후 일부 사용자 관련 정보, 사용자 역할 또는 만료 시간 등을 현재 세션에 저장합니다. 3. 서버는 사용자에게 session_id를 제공하고 이를 사용자의 쿠키에 쓰거나 클라이언트가 이를 로컬에 저장합니다. 4. 사용자가 서비스를 요청할 때마다 쿠키나 기타 방법을 통해 이 session_id를 가져와야 합니다. 5. 서버는 이를 수신한 후 데이터베이스로 돌아가 현재 session_id를 쿼리하고 사용자에게 권한이 있는지 확인합니다.
이 모델의 장점은 서버가 언제든지 사용자의 권한을 종료할 수 있고 데이터베이스로 이동하여 현재 사용자의 세션 정보를 수정하거나 삭제할 수 있다는 것입니다. 그러나 단점도 있습니다. 즉, 서버 클러스터인 경우 각 서버가 동일한 세션 저장 정보를 얻을 수 있도록 모든 시스템이 세션 정보를 공유해야 한다는 것입니다. 이러한 문제는 해결될 수 있지만 작업량이 엄청납니다.
JWT 솔루션의 장점은 이 정보가 저장되지 않는다는 것입니다. 토큰 데이터는 요청이 승인될 때마다 확인만 하면 됩니다.
JWT의 원리에 대해 간단히 이야기해 보겠습니다. 실제로 클라이언트가 인증 요청을 보내면 서버는 사용자를 인증한 후 JSON 개체를 생성합니다. 여기에는 "당신은 누구입니까, 무엇을 하는가 등과 같은 정보가 포함될 수 있습니다." ., 만료 시간 " , 중요한 것은 만료 시간이 있어야 한다는 것입니다. 일반적인 형식은 다음과 같습니다.
{ 사용자 이름: "thief string er", 역할: "월드 코드 파머", endTime: "2022년 5월 20일" }
하지만 그렇게 피상적인 방식으로 전달되지는 않습니다. 지정된 서명 알고리즘과 제출한 페이로드에 대한 일부 정보를 기반으로 하는 가역적 서명 알고리즘을 통해 서명되고 전송됩니다. 일반적인 형식을 나타내기 위해 사진을 사용하겠습니다. :
그림에서 볼 수 있듯이 반환된 정보는 크게 세 부분으로 나누어져 있습니다. 왼쪽은 서명 후 결과이며, 오른쪽도 디코딩된 소스 코드입니다. 빨간색, 보라색, 청록색의 세 가지 색상은 각각 "점"으로 구분됩니다.
첫 번째 빨간색 부분은 헤더입니다. 헤더는 주로 방법을 지정합니다. 그림의 서명 알고리즘( 기본값 HS256 )은 SHA-256을 사용하는 대칭 알고리즘입니다. 필드 식별자는 JWT 유형입니다.
두 번째 보라색 부분인 페이로드는 전송될 실제 데이터인 JSON 개체입니다. 사용할 수 있는 공식 필드는 7개입니다.
iss (발행자): 발행자
exp (만료 시간): 만료 시간
하위 (주제) : 주제
aud (청중) : 청중
nbf(이전 아님): 유효 시간
iat (Issued At) : 발급 시간
jti (JWT ID): 숫자
이러한 필드 외에도 일부 사용자 정의 필드를 생성할 수도 있습니다. JWT는 기본적으로 암호화되지 않으므로 사용할 때 민감한 데이터를 사용하지 않도록 주의하세요.
세 번째 부분은 Signature
서명입니다. 이 부분은 귀하가 지정하는 비밀 키로 서버에만 존재하며, 헤더에 지정된 알고리즘을 사용하여 다음 서명 방법을 통해 서명합니다.
아래의 구체적인 사용을 경험해 보겠습니다.
1단계: nodejs 프로젝트를 빌드해야 합니다. npm init -y
통해 프로젝트를 초기화한 다음 express
, jsonwebtoken
및 nodemon
포함한 종속성을 설치해야 합니다.
$ npm 나는 jsonwebtoken nodemon을 표현합니다.
그런 다음 package.json
의 scripts
필드에 nodemon app.js
명령을 추가합니다.
"스크립트": { "start": "nodemon app.js" },
2단계: 노드 애플리케이션을 초기화하고 루트 디렉터리에 app.js 파일을 만듭니다.
// app.js const express = require("표현하다"); const 앱 = 표현(); app.use(express.json()); app.listen(3000, () => { console.log(3000 + "listening..."); // 포트 3000 듣기});
3단계: jsonwebtoken
종속성을 도입하고 인터페이스와 서버의 개인 키를 생성합니다.
// app.js //... const jwt = require("jsonwebtoken"); const jwtKey = "~!@#$%^&*()+,"; // ...
여기서 jwtKey
서버에만 저장되는 사용자 정의 개인 키입니다. 이후 로그인을 위한 /login 인터페이스 작성을 시작하고 검증을 위한 로컬 시뮬레이션 데이터베이스를 생성한 후 jwt.sign
메소드를 통해 수행했습니다. 서명 확인:
// app.js const 데이터베이스 = { 사용자 이름: "사용자 이름", 비밀번호: "비밀번호", }; app.post("/login", (req, res) => { const { 사용자 이름, 비밀번호 } = req.body; if (사용자 이름 === 데이터베이스.사용자 이름 && 비밀번호 === 데이터베이스.비밀번호) { jwt.sign( { 사용자 이름, }, jwt키, { 만료일: "30S", }, (_, 토큰) => { res.json({ 사용자 이름, 메시지: "로그인 성공", 토큰, }); } ); } });
위 코드에서는 post
을 확인하기 위해 로컬 계정 및 비밀번호 데이터베이스 생성을 시뮬레이션하기 위한 database
만든 다음, 계정과 비밀번호 /login
완전히 일치하는지 확인한 후 jsonwebtoken
통해 가져왔습니다. 패키지에 서명하려면 jwt
객체 아래의 sign
메소드를 사용하세요.
함수 기호 내보내기( 페이로드: 문자열 | secretOrPrivateKey: 비밀, 옵션?: SignOptions, ): 끈; 함수 기호 내보내기( 페이로드: 문자열 | secretOrPrivateKey: 비밀, 콜백: SignCallback, ): 무효의; 함수 기호 내보내기( 페이로드: 문자열 | secretOrPrivateKey: 비밀, 옵션: SignOptions, 콜백: SignCallback, ): 무효의;
여기서는 함수 오버로딩 방법을 사용하여 인터페이스를 구현합니다. 첫 번째 매개변수는 사용자 정의 개체 유형, Buffer
유형 또는 직접 string
object
수 있습니다. JWT는 서명 시 이러한 데이터에도 서명하기 때문에 일부 필드를 사용자 정의합니다. 그러나 JWT는 기본적으로 암호화 되지 않으므로 여기서는 중요한 데이터를 사용하지 않아야 한다는 점에 유의할 가치가 있습니다. 변조되지 않았으며 서명을 확인하는 과정을 검증 이라고 합니다.
물론 원본 토큰을 암호화한 후 전송할 수도 있습니다.
두 번째 매개변수는 서명을 위해 서버에 저장하는 비밀 키입니다. 일반적으로 JWS는 JWA에서 제공하는 HS256 알고리즘과 키를 사용합니다. 그러나 분산 시나리오에서는 키에 의존합니다. 여러 서비스에서 JWT 검증이 필요할 수 있으며, 각 서비스에 키를 저장하면 보안이 크게 저하됩니다. 일단 키가 유출되면 누구나 마음대로 JWT를 위조할 수 있다는 점을 알아야 합니다.
세 번째 매개변수는 인터페이스의 서명인 SignOptions
서명 옵션입니다.
내보내기 인터페이스 SignOptions { 알고리즘?: 알고리즘이 정의되지 않음; 키 ID?: 문자열 | 정의되지 않음; 만료?: 문자열 | /** 초 또는 시간 범위를 설명하는 문자열 [zeit/ms](https://github.com/zeit/ms.js)로 표시됩니다. 예: 60, "2 days", "10h", "7d" */ notBefore?: 문자열 | 청중?: 문자열 | 제목?: 문자열 | 정의되지 않음; 발급자?: 문자열 | 정의되지 않음; jwtid?: 문자열 | 정의되지 않음; mutatePayload?: 부울 | 정의되지 않음; noTimestamp?: 부울 | 헤더?: JwtHeader | 정의되지 않음; 인코딩?: 문자열 | 정의되지 않음; }
여기서는 expiresIn
필드를 사용하여 에이징 시간을 지정합니다. 사용 방법은 이 문서를 참조하세요.
네 번째 매개변수는 콜백입니다. 콜백의 두 번째 매개변수는 서명을 통해 생성된 token
입니다. 마지막으로 이 token
프런트엔드에 로컬로 저장되고 확인을 위해 서버로 가져올 수 있도록 반환됩니다. 모든 요청에.
다음으로 이 인터페이스를 확인해 보겠습니다. vscode에 REST 클라이언트 플러그인을 설치한 다음 루트 디렉터리에 request.http
파일을 만들고 요청된 정보를 파일에 썼습니다.
POST http://localhost:3000/login 콘텐츠 유형: 애플리케이션/json { "사용자 이름": "사용자 이름", "비밀번호": "비밀번호" }
그런 다음 명령줄에서 npm run start
명령을 실행하여 서비스를 시작한 다음 requset.http
파일 위의 Send Request
버튼을 클릭하여 요청을 보냅니다.
요청이 성공하면 다음과 같은 응답 메시지가 표시됩니다.
token
필드는 JWT에서 생성된 token
입니다.
이 token
이 유효한지 검증해 보겠습니다. 로그인 후 인터페이스를 작성합니다.
app.get("/afterlogin", (req, res) => { const { 헤더 } = 요청; const 토큰 = headers["authorization"].split(" ")[1]; //헤더의 인증 필드에 토큰을 넣습니다. jwt.verify(token, jwtKey, (err, payload) => { if (err) return res.sendStatus(403); res.json({ 메시지: "인증 성공", 페이로드 }); }); });
이 코드에서는 이전에 JWT를 통해 생성된 token
요청 헤더의 authorization
필드에서 token
획득하여 얻습니다. 그런 다음 jwt.verify
확인 메서드를 호출하여 token
이 유효한지 확인합니다. 이 메서드에는 세 가지 매개변수가 있습니다.
// 네 가지 인터페이스 서명이 있습니다. 문서를 직접 확인할 수 있습니다. 내보내기 함수 verify( 토큰: 문자열, //확인이 필요한 토큰 secretOrPublicKey: 비밀 GetPublicKeyOrSecret, // 서버 콜백에 정의된 서명 키?: verifyCallback<JwtPayload | // 검증정보 결과를 얻기 위한 콜백): void;
다음으로 방금 응답한 token
요청 헤더에 복사합니다.
### GET http://localhost:3000/afterlogin 승인: 무기명 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwiaWF0IjoxNjUyNzg5NzA3LCJleHAiOjE2NTI3ODk3Mzd9.s9fk3YLhxTUcpUgCfIK4xQ N58 Hk_XEP5y9GM9A8jBbY
이전 Bearer 인증은 http 프로토콜의 표준 인증 방법입니다.
또한 Send Request
클릭하고 아래 그림에 응답이 표시되면 응답이 성공한 것입니다.
사실 위의 내용은 JWT의 몇 가지 간단한 용도입니다. 다음으로 JWT 자체의 장점과 단점에 대해 이야기해 보겠습니다.
JWT가 차지하는 저장 공간은 실제로 작지 않습니다. 너무 많은 정보에 서명해야 하면 토큰이 쿠키의 길이 제한을 초과할 가능성이 높습니다. 예를 들어 다음 두 그림을 비교해 보세요.
분명히 페이로드의 정보량이 증가하면 토큰의 길이도 늘어납니다.
보안상 실제로 token
너무 많은 공간을 차지할 경우 Cookie
최대 저장공간은 4kb에 불과하며, 프론트 엔드는 localStorage
등의 로컬 저장소에 저장할 수 있지만 배치하지 않으면 문제가 발생합니다. 쿠키에서는 보안이 크게 저하됩니다. js 스크립트를 통해 쿠키를 얻을 위험이 있습니다. 이는 모든 해커가 쿠키를 사용하여 무엇이든 할 수 있음을 의미합니다.
실제로 JWT의 특정 측면은 사용자 token
지속적으로 저장할 필요가 없다는 것입니다. 대신에 방금 본 것처럼 token
에는 만료 시간도 포함됩니다. 만료 시간이 변경되면 token
변조됩니다. 만료 날짜를 저장하고 수동으로 변경할 수 있는 방법이 없기 때문에 사용자가 두 번 로그인하여 두 개의 token
token
생성되면 즉시 삭제하기가 어렵습니다. 원칙적으로 두 개의 token
모두 유효합니다.
위의 내용은 주로 몇 가지 사항에 대해 설명합니다.
JWT의 원칙은 주로 서버의 개인 키를 사용하여 JSON 서명으로 생성된 token
과 통신하는 것입니다.
또한 헤더에서 서명 알고리즘 및 유형을 지정하는 데 사용되는 JWT의 내부 데이터 구성, JSON 데이터를 전송하는 페이로드, 데이터에 서명 알고리즘을 수행하고 변조를 방지하는 서명에 대해 소개합니다.
nodejs를 통해 JWT를 사용하는 방법, sign
메소드를 통해 데이터 서명을 수행하는 방법, verify
메소드를 통해 서명 검증을 수행하는 방법에 대해 자세히 소개합니다.
JWT의 몇 가지 단점도 소개됩니다.
하나는 서명 데이터의 양이 증가함에 따라 저장 공간이 증가한다는 것입니다.
그리고 보안이 있습니다. 저장 공간이 너무 크면 상대적으로 보안 수준이 높은 Cookie
에 저장되지 않아 마음대로 스크립트를 얻을 수 있습니다.
그리고 token
의 적시성을 유연하게 제어할 수 없는 적시성이 있습니다.
위의 참고용 nodejs 데모 소스코드 입니다.