O que é JWT? Este artigo irá levá-lo a entender o JWT, apresentar a aplicação do JWT no nó e as vantagens e desvantagens do JWT. Espero que seja útil para todos!
JWT é a abreviatura de JSON Web Token , que é uma solução de autenticação no ambiente de aplicação de rede. No mecanismo de autenticação tradicional nada mais é do que as seguintes etapas:
1. O usuário envia a senha da conta ao servidor; 2. Depois que o servidor verificar a senha da conta, ele salvará algumas informações relacionadas ao usuário, funções do usuário ou tempo de expiração, etc. 3. O servidor fornece ao usuário um session_id e o grava no cookie do usuário ou o cliente o salva localmente; 4. Toda vez que o usuário solicitar um serviço, ele precisará trazer esse session_id, talvez através de cookies ou outros métodos; 5. Após o recebimento, o servidor volta ao banco de dados para consultar o session_id atual e verifica se o usuário tem permissão;
Uma vantagem deste modelo é que o servidor pode encerrar as permissões do usuário a qualquer momento e pode ir ao banco de dados para modificar ou excluir as informações da sessão do usuário atual. Mas também há uma desvantagem, ou seja, se for um cluster de servidores, todas as máquinas precisam compartilhar as informações da sessão para garantir que cada servidor possa obter as mesmas informações de armazenamento da sessão. Embora estes problemas possam ser resolvidos, a quantidade de trabalho é enorme.
A vantagem da solução JWT é que essas informações não são salvas. Os dados do token são salvos no cliente. Cada vez que uma solicitação é aceita, ela só precisa ser verificada.
Vamos falar brevemente sobre o princípio do JWT. Na verdade, quando o cliente envia uma solicitação de autenticação, o servidor irá gerar um objeto JSON após autenticar o usuário, que provavelmente inclui informações como "quem é você, o que você faz, etc.". ., expiration time " , o importante é que deve haver um prazo de expiração; o formato geral é:
{ nome de usuário: "ladrão string er", função: "Fazendeiro do Código Mundial", endTime: "20 de maio de 2022" }
Mas não será passado para você de forma tão superficial. Ele será assinado e transmitido por meio de um algoritmo de assinatura reversível baseado no algoritmo de assinatura especificado e em algumas informações sobre a carga que você enviou. Usarei uma imagem para representar o formato geral. :
Como pode ser visto na imagem, as informações retornadas são divididas aproximadamente em três partes. O lado esquerdo é o resultado após a assinatura, que é o resultado retornado ao cliente. O lado direito também é o código-fonte decodificado. separados por "pontos", respectivamente. Existe uma correspondência um-para-um entre as três cores vermelho, roxo e ciano:
A primeira parte vermelha é o cabeçalho. O cabeçalho especifica principalmente o método. O algoritmo de assinatura na imagem ( padrão HS256 ) é HMAC com SHA-256. o identificador do campo é do tipo JWT;
A segunda parte roxa, payload, é um objeto JSON, que são os dados reais a serem transmitidos. Existem sete campos oficiais que podem ser usados:
iss (emissor): emissor
exp (tempo de expiração): tempo de expiração
sub (assunto): assunto
aud (público): audiência
nbf (não antes): tempo efetivo
iat (emitido em): horário de emissão
jti (ID JWT): número
Além desses campos, você também pode criar alguns campos personalizados. Como o JWT não é criptografado por padrão, tome cuidado para não usar alguns dados confidenciais ao usá-lo.
A terceira parte é a Signature
. Esta parte é uma chave secreta especificada por você e existe apenas no servidor e, em seguida, usa o algoritmo especificado no cabeçalho para assinar por meio do seguinte método de assinatura.
Vamos experimentar o uso específico abaixo:
Passo 1: Precisamos construir um projeto nodejs; inicializar um projeto através de npm init -y
; então precisamos instalar dependências, incluindo express
, jsonwebtoken
e nodemon
;
$ npm eu expresso jsonwebtoken nodemon
Em seguida, adicione o comando nodemon app.js
no campo scripts
em package.json
:
"roteiros": { "iniciar": "nodemon app.js" },
Etapa 2: inicialize o aplicativo do nó e crie o arquivo app.js no diretório raiz;
//aplicativo.js const expresso = requer("expresso"); const app=express(); app.use(express.json()); app.listen(3000, () => { console.log(3000 + "escutando..."); // Escuta a porta 3000});
Passo 3: Introduza jsonwebtoken
e crie a chave privada da interface e do servidor;
//aplicativo.js //... const jwt = require("jsonwebtoken"); const jwtKey = "~!@#$%^&*()+,"; // ...
jwtKey
aqui é nossa chave privada personalizada que só é salva no servidor. Depois disso, começamos a escrever uma interface /login para login, criamos um banco de dados de simulação local para verificação e executamos através do método jwt.sign
. Verifique a assinatura:
//aplicativo.js banco de dados const = { nome de usuário: "nome de usuário", senha: "senha", }; app.post("/login", (req, res) => { const {nome de usuário, senha} = req.body; if (nome de usuário === banco de dados.nome de usuário && senha === banco de dados.senha) { jwt.sign( { nome de usuário, }, jwtKey, { expira em: "30S", }, (_, token) => { res.json({ nome de usuário, mensagem: "Login bem-sucedido", ficha, }); } ); } });
No código acima, criamos database
para simular a criação jsonwebtoken
um banco de dados local de contas e senhas para verificar o login; em seguida, estabelecemos uma interface post
/login
. pacote Use o método sign
no objeto jwt
para assinar.
sinal de função de exportação ( carga útil: string | objeto buffer | secretOrPrivateKey: segredo, opções?: SignOptions, ): corda; sinal de função de exportação ( carga útil: string | objeto buffer | secretOrPrivateKey: segredo, retorno de chamada: SignCallback, ): vazio; sinal de função de exportação ( carga útil: string | objeto buffer | secretOrPrivateKey: segredo, opções: SignOptions, retorno de chamada: SignCallback, ): vazio;
O método de sobrecarga de função é usado aqui para implementar a interface. Implementaremos a última assinatura da interface aqui. O primeiro object
pode ser um tipo de objeto personalizado, um tipo Buffer
ou diretamente um tipo string
. e personaliza alguns campos, pois o JWT também assinará esses dados ao assinar. Porém, é importante ressaltar que você deve tentar não usar dados confidenciais aqui porque o JWT não é criptografado por padrão . não foi adulterado e o processo de verificação da assinatura é chamado de verificação .
Claro, você também pode criptografar o token original e depois transmiti-lo;
O segundo parâmetro: é a chave secreta que salvamos no servidor para assinatura. Geralmente no modo cliente-servidor, o JWS usa o algoritmo HS256 fornecido pelo JWA mais uma chave. vários serviços podem precisar verificar o JWT. Se a chave for salva em cada serviço, a segurança será bastante reduzida. Você deve saber que, uma vez que a chave for vazada, qualquer pessoa poderá falsificar o JWT.
O terceiro parâmetro: é a opção de assinatura SignOptions
, a assinatura da interface:
interface de exportação SignOptions { algoritmo?: Algoritmo indefinido; keyid?: string | indefinido; expiraIn?: string | número indefinido; /** expresso em segundos ou uma string descrevendo um intervalo de tempo [zeit/ms](https://github.com/zeit/ms.js. Ex.: 60, "2 dias", "10h", "7d"). */ notBefore?: string | número indefinido; público?: string | string[] | assunto?: string | indefinido; emissor?: string | indefinido; jwtid?: string | indefinido; mutatePayload?: booleano | indefinido; noTimestamp?: booleano | cabeçalho?: JwtHeader | indefinido; codificação?: string | indefinido; }
Aqui usamos o campo expiresIn
para especificar o tempo de envelhecimento. Consulte este documento para obter métodos de uso;
O quarto parâmetro é um retorno de chamada. O segundo parâmetro do retorno de chamada é token
que geramos por meio da assinatura. Finalmente, esse token
é retornado ao front-end para que possa ser armazenado localmente no front-end e levado ao servidor para verificação. em cada solicitação.
A seguir, vamos verificar esta interface: instalei o plug-in REST Client no vscode e, em seguida, criei um arquivo request.http
no diretório raiz e escrevi as informações solicitadas no arquivo:
POSTAR http://localhost:3000/login tipo de conteúdo: aplicativo/json { "nome de usuário": "nome de usuário", "senha": "senha" }
Em seguida, execute o comando npm run start
na linha de comando para iniciar o serviço e clique no botão Send Request
acima do arquivo requset.http
para enviar a solicitação:
Depois que a solicitação for bem-sucedida, você verá uma mensagem de resposta como esta:
O campo token
é token
gerado pelo nosso JWT;
Vamos verificar se este token
é válido. Estamos escrevendo uma interface após o login:
app.get("/afterlogin", (req, res) => { const {cabeçalhos} = req; const token = headers["autorização"].split(" ")[1]; //Coloque o token no campo de autorização do cabeçalho jwt.verify(token, jwtKey, (err, payload) => { se (errar) retornar res.sendStatus(403); res.json({ mensagem: "Autenticação bem-sucedida", carga útil }); }); });
Neste código, token
gerado anteriormente através do JWT é obtido através da obtenção token
no campo authorization
no cabeçalho da solicitação. Em seguida, verifique se o token
é válido chamando jwt.verify
. Este método possui três parâmetros:
// Existem quatro assinaturas de interface, você mesmo pode verificar a documentação export function verify( token: string, //Token que precisa ser verificado secretOrPublicKey: segredo | GetPublicKeyOrSecret, // A chave de assinatura definida no retorno de chamada do servidor?: VerifyCallback<JwtPayload string>, // Callback para obter o resultado da informação de verificação): void;
A seguir, copiamos token
que acabamos de responder no cabeçalho da solicitação:
### OBTER http://localhost:3000/afterlogin autorização: Portador eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwiaWF0IjoxNjUyNzg5NzA3LCJleHAiOjE2NTI3ODk3Mzd9.s9fk3YLhxTUcpUgCfIK4xQ 58Hk_XEP5y9GM9A8jBbY
A autenticação Bearer anterior é o método de autenticação padrão no protocolo http.
Clique também em Send Request
e quando você vir a resposta na imagem abaixo, significa que a resposta foi bem-sucedida:
Na verdade, os itens acima são alguns usos simples do JWT. A seguir, vamos falar sobre as vantagens e desvantagens do próprio JWT.
O espaço de armazenamento ocupado pelo JWT não é pequeno. Se precisarmos assinar muitas informações, o token provavelmente excederá o limite de comprimento do cookie. Por exemplo, compare estas duas imagens:
Obviamente, à medida que a quantidade de informações na carga útil aumenta, o comprimento do token também aumentará;
Segurança, na verdade, se token
ocupar muito espaço, o espaço máximo de armazenamento Cookie
será de apenas 4kb. O front-end pode ser armazenado em armazenamento local, como localStorage
, mas causará um problema se não for colocado. no cookie, a segurança será bastante reduzida. Haverá o risco de obtê-lo através do script js, o que significa que qualquer hacker pode fazer qualquer coisa com ele;
Oportunidade inflexível Na verdade, um certo aspecto do JWT é que o token
do usuário não precisa ser armazenado de forma persistente. Em vez disso, token
é efetivamente verificado usando a verificação do servidor. o tempo de expiração for alterado, token
será adulterado. Como não há como armazenar e alterar manualmente a data de expiração, é difícil excluir o token
imediatamente. Se o usuário fizer login duas vezes e dois token
forem gerados, então. princípio, dois token
serão gerados, todos válidos;
O texto acima fala principalmente sobre alguns pontos:
O princípio do JWT é principalmente usar a chave privada do servidor para se comunicar com token
gerado pela assinatura JSON;
Ele também apresenta a composição dos dados internos do JWT, que é usado pelo Header para especificar o algoritmo e o tipo de assinatura, a carga útil para transmitir dados JSON e a Signature para executar o algoritmo de assinatura nos dados e evitar adulterações;
É fornecida uma introdução detalhada sobre como usar JWT por meio de nodejs, realizar assinatura de dados por meio do método sign
e realizar verificação de assinatura por meio do método verify
;
Algumas desvantagens do JWT também são introduzidas:
Uma é que o espaço de armazenamento aumenta à medida que aumenta a quantidade de dados de assinatura;
Depois, há segurança. Se o espaço de armazenamento for muito grande, ele não será armazenado em Cookie
com nível de segurança relativamente alto, fazendo com que o script seja obtido à vontade;
Depois, há a oportunidade, que não pode controlar de forma flexível a oportunidade dos token
;
Este é o código-fonte de demonstração do nodejs acima para referência;