ユーザーのログインと登録を含むすべてのプロジェクトには、ユーザーのログインステータスを確認するためのログイン状態が必要です。一般的に使用されるログインデスクは、トークン、セッション、その他の識別子にすぎません。ここでは、tokenフィールドを使用しています。トークンには通常、アカウント番号、アカウントID、ユーザー名などのユーザーの個人情報が含まれています。カスタムソルト(塩)を追加して暗号化すると、ユーザー情報の漏洩を防ぐことができます。一緒に使ってみましょう:
トークンといえば、フロントエンドから渡されたトークンが、私が渡した有効な値であるかどうかをバックエンドがどのようにして知るのか、私は間違いなく思いますか?つまり、有効性を知るには、フロントエンドから渡されたトークンと比較する値がバックエンドにある必要があります。したがって、バックエンドがトークンを生成するとき、生成されたトークンを保存して使用する必要があります。ここでredisを選択しました。これはデータベースであり、キーと値のペアの形式で格納されるため、生成されたトークンを格納できます。redisのインストールとデプロイについては、ここでは面倒ではなく、ここで直接使用されます。
プロジェクトのルートディレクトリにredisフォルダーを作成します。その下にredis.jsファイルを作成します。
//redis.js
const Redis = require('ioredis')//导入模块
const redis = {
port: 6379, // Redis port
host: '127.0.0.1', // Redis host
prefix: '***', //存诸前缀
ttl: 60 * 60 * 24 * 7 * 1000, //过期时间
family: 4,
db: 0
}
const redisClient = new Redis(redis)
//导出备用
module.exports = redisClient
したがって、redisを使用できます。
この記事では、暗号化と復号化にjsonwebtokenを使用しています。
暗号化と復号化は多くのインターフェースで使用する必要があるものなので、これらのメソッドをパブリック部分に書き込みます。
common.jsは、utilsファイルの下に構築され、パブリックメソッドを格納します。
//common.js
const secret = require('./secret')//导入自定义的盐
const jwt = require('jsonwebtoken')//导入jsonwebtoken
const verify = util.promisify(jwt.verify) // token解密
const common = {
//定义一个对象
//加密
//后端生成唯一的key
/*
* paylod:包含来用户的信息
* secret.secret 自定义的盐(salt)
* expiresIn 设置这个token的有效期
*/
//jwt.sign是jsonwebtoken模块的一个方法,可以将传入的信息加密
getToken(paylod, expiresIn) {
return jwt.sign(paylod, secret.secret, expiresIn)
},
//解密
//根据收到的token获取用户信息
getUserInfo(token) {
return verify(token, secret.secret)
},
}
//导出这个对象给外部使用
module.exports=common
カスタム情報を格納する新しいsecret.jsファイルを作成します
⚠️ここでは、ソルトはランダムな方法で書くことをお勧めします。すべての種類の文字を追加して、順序を乱して書きます。
暗号化
ユーザーが正常にログインすると、ユーザー情報が暗号化されます。そこで、管理者ログインインターフェイスに書き込みます。
ルートファイルの下の私のadmin.jsファイル
//admin.js
const router = require('koa-router')()
const api = require('../controllers/api')
const redisClient = require('../redis/redis.js')
const common = require('../util/comon')
router.prefix('/admin')
//管理员登录
router.post('/userLogin', async (ctx, next) => {
/*写你的接口逻辑*/
//定义一个用户信息对象
const paylod = {
name: '登录用户的用户名',
userid: '登录用户的id',//登录时可查表查拿到用户id
author: '[email protected]',
type:'***',
timestamp: new Date()//加个时间戳保证加密后token的唯一性
}
/*核心代码*/
// 调用上面公共的token加密方法(注:这里是没有传盐进去的,我是直接在common文件引入来盐)
// expiresIn设置token的有效期是7天
const token = await common.getToken(paylod, {
expiresIn: '7 days' })
//每次登录之前先清除掉所有的有关此用户的key(根据用户id)
let preToken = await redisClient.get(result.userid)
//这个preToken就是当初登录时redis存下来的key
await redisClient.del(preToken)
//用token作为key、自定义的token前缀+token作为值 传key给前端作为校验
await redisClient.set(token, secret.identif + token)
//再生成一对键值对 用来记录是属于哪个用户的token 用户id作为key 传给前端的token(上一条键值对的key)作为值
await redisClient.set(result.userid,token)
ctx.body = {
status: 200,
code: 200,
message: '登录成功',
data: result,
token: token//将token传给前端
}
}
このようにして、ログインが成功した後、フロントエンドはバックエンドによって生成された一意のトークンを受け取ることができ、2組のキーと値のペアも生成しました。1つのペアはトークンをキーとして使用し、カスタムトークンプレフィックスを値として使用します。1つのペアはユーザーIDをキーとして使用し、トークンを値として使用します。ユーザーがログインするときにユーザーIDを取得し、このユーザーIDをキーとしてredisのレコードをクリアしてから、トークンをキーとしてレコードを保存します。このようにして、ユーザーがログインするたびに、ユーザーが1つの正当なキーのみを持つことを保証できます(複数の場所での同じアカウントのいわゆるログインステータスは、他の人のログインステータスを混雑させます)。
解読する
暗号化が完了した後、クライアント要求はデータを操作するためにログイン状態トークンをもたらす必要がありますが、クライアント側でユーザーのデータを送信することは不可能です。これはセキュリティが高すぎるため、上記のトークンを生成するときにユーザー情報を追加したデータに便利ですが、それを解読する限り、このトークンによって運ばれるユーザー情報を知ることができます。このトークンクライアントは、ユーザー情報を見ても認識しないため、比較的安全です。
common.jsでは、フロントエンドから渡されるトークンを記述しました(パラメーターの形式ではなく、リクエストヘッダーを介して渡されます)
//common.js
//根据请求头的信息获取前端传入的token
getHeaderToken(ctx) {
if (ctx.header && ctx.header.token) {
return ctx.header.token
}
}
const common = require('../util/comon')
//删除管理员
router.post('/****', async (ctx, next) => {
let token = await common.getHeaderToken(ctx)
let userInfo = await common.getUserInfo(token)
//用户名
console.log(userInfo.name)
//用户id
console.log(userInfo.userid)
}
したがって、フロントエンドがトークンを渡す限り、バックエンドはトークンによって運ばれるユーザーの情報を知ることができ、バックエンドがデータを処理するために必要な条件を容易にします。
上記は、トークンの使用に関するこの紹介ですが、以下では、ログインコンソールコントロールインターフェースに基づいて権限をリクエストする方法を紹介します。