加密token认证

735 阅读6分钟

加密技术

现代密码学设计原则

柯克霍夫原则: 数据的安全基于密钥而不是算法的保密。即系统的安全取决于密钥,对密钥保密,对算法公开

常用加密码算法

对称加密

  • 指加密和解密使用相同密钥的加密算法。对称加密算法的原理很容易理解,通信一方用KEK加密明文,另一方收到之后用同样的KEY来解密就可以得到明文。

image.png

  • 常见的对称加密算法有DES、3DES、Blowfish、IDEA、RC4、RC5、RC6和AES

  • 优点: 对称加密算法的优点是算法公开、计算量小、加密速度快、加密效率高。

  • 缺点: 没有非对称加密安全.

  • 用途: 一般用于保存用户手机号、身份证等敏感但能解密的信息。

  • 示例-crypto.js库
    安装方式一: npm install crypto-js
    安装方式二: 引用文件

/*
 * 加密
 * message: 明文
 * key: 秘钥
 */
function encryptText(message, key) {
    return CryptoJS.AES.encrypt(message, key).toString() // 加密码
}

/**
 * 解密
 * cipherText: 密文
 * key: 秘钥
 */
function decryptText(cipherText, key) {
    var bytes = CryptoJS.AES.decrypt(cipherText, key)
    var originalText = bytes.toString(CryptoJS.enc.Utf8)
    return originalText
}

/**
 * 测试对称加密
 */
function testEncrypt() {
    let msg = '2022年10月1 国庆放假'
    let key = 'h52208_key'
    let cipherText = encryptText(msg, key)
    // U2FsdGVkX1/3hYWvhOn5aGQlde/4w/hxLqoE2o3DLnmkYzobaaL74GSEEYrvANC2
    console.log(cipherText)
    
    let text = decryptText(cipherText, 'h52208_key')
    console.log(text)
}

非对称加密

非对称加密算法,使用两把完全不同但又是完全匹配的一对Key:公钥和私钥。
在使用非对称加密算法加密文件时,只有使用匹配的一对公钥和私钥,才能完成对明文的加密和解密过程。

image.png

  • 优点: 非对称加密与对称加密相比,其安全性更好;
  • 缺点: 非对称加密的缺点是加密和解密花费时间长、速度慢,只适合对少量数据进行加密。
  • 用途: 一般用于签名和认证。私钥服务器保存, 用来加密, 公钥客户拿着用于对于令牌或者签名的解密或者校验使用.
  • 常见的非对称加密算法有: RSA、DSA(数字签名用)、ECC(移动设备用)、RS256 (采用SHA-256 的 RSA 签名)
  • 规则:公钥加密,私钥解密
  • RSA加密
    • RSA秘钥生成方式
      Mac系统内置OpenSSL(开源加密库),所以可以直接在终端上使用命令。
      Windows系统可以使用git命令行工具,单击鼠标右键——git bash here调出git bash,生成私钥,密钥长度为1024bit
      从私钥中提取公钥
      命令行查看
      RSA在线生成:toolsjb51.net/password/rs…

    • rsa加解密库jsencrypt

引入<script src="../lib/js/JSEncrypt.js"></script>

npm install jsencrypt

```
/**
 * 加密
 */
function encryptMsg(message){
    let publicKey = `-----BEGIN PUBLIC KEY-----
    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdjI9iz4LVwswO5n7xiXv8Zl1Z
    HGifqjH7nHN7OCxAMEipxLov2FFCepl4wJPaodqZkUX64kfc2fAM2Zyo6x1v08DR
    ln+74iw/7F9ZiQ4eO581iMHA6WCNtLs1K5RkqozSqOiwo6J/C8iZNnE63foIIk+D
    f9kovGgOF5k/7DvSiwIDAQAB
    -----END PUBLIC KEY-----`
    let jsEncrypt = new JSEncrypt()
    jsEncrypt.setPublicKey(publicKey) //设置公钥
    let encryMessage = jsEncrypt.encrypt(message) //加密message
    return encryMessage
}

/**
 * 解密
 */
function decodeMsg(encryMsg){
    let privateKey = `-----BEGIN RSA PRIVATE KEY-----
    MIICXQIBAAKBgQDdjI9iz4LVwswO5n7xiXv8Zl1ZHGifqjH7nHN7OCxAMEipxLov
    2FFCepl4wJPaodqZkUX64kfc2fAM2Zyo6x1v08DRln+74iw/7F9ZiQ4eO581iMHA
    AoGAMbbCzhdmcnUduRI71hNVwRNvSvm2+G0GfkFjIHlAZL7w7zd32BigU1yTZ6c/
    BkZfeSpCG8P/AC3fUeLa5oSru+s7rWE/4i55C7QDRMQqrxZT2SSiyZxw37dKaFld
    sASFmd7eDbWNcFedjQ9Z77P5khPzRsPbDaTzl2CW52jDqOECQQD4lfvzkd/ZtRn6
    5dYCLjAoQVkFE4CUXyCf5S25hqlnFXylEuBQ2Vr8XR3FtGr1uVrEoa7APxtoJb5g
    ij8C5ZB5AkEA5Cgknf+FXttPWwTeF6XnuLmcKp+OBPSuSdLMKIWusQDIGRL5lj0U
    PEyWwUimBoUoqCBT10eVE1dMrtZS1rEiIwJATwsqBUYiPtCmRTBl/2V+bJ5y1vlf
    jk49SnqOMosOPLgJXVgGOc8TbmGRgPcgd6gLo7Chp4GpjlFKGtp6tMoYSQJBAKa2
    CmOEhOCV4TtBqEKhUFszDMA8S9qlKwD4TYNCgy4EwzFHIyY7RSD2WaWrvty+ycFn
    tbt1K6GxRW/vXSJQ1f8CQQDaSBq7LvSPrcI8FqyEe/Js0Mfascojuh+VIuA1J2de
    K4tFxK7Zri3p/I9ZNUcrbFLJeZuauTWFdG18ZN7NH7M0
    -----END RSA PRIVATE KEY-----`
    let jsEncrypt = new JSEncrypt()
    jsEncrypt.setPrivateKey(privateKey)
    let message = jsEncrypt.decrypt(encryMsg) //解密
    return message
}
```

不可逆加密算法

Hash算法特别的地方在于它是一种单向算法,一旦加密就不能反向解密得到密码原文。常用在不可还原的密码存储、信息完整性校验等。

  • 常见的不可逆加密算法有: MD5、SHA、HMAC
  • SHA
    js-sha256库
    npm i js-sha256
<script src="../ib/js/sha256,js"></script> //引入sha.js文件
<script>
    var encodeText = sha256('明天放假');
    console.log('encodeText >>> ', encodeText);
    //9ed6896513a64af764aef508a53d66C3a2fab162f6b1cd2e31e823a8524741b9
</script>

base64

Base64并不是一种加密方式,明文使用Base64编码后的字符串通过索引表可以直接还原为明文。因此,Base64只能作为一种数据的存储格式

  • base64实现
    • 安装npm install js _base64
    • let Base64 = require(js-base64).Base64//还是rquire
    • this.pw = Base64.encode(this.passWord)//还是那些操作
  • 在线编码工具:www.jsons.cn/img2base64/

token认证

Token身份验证

流程:

  1. 客户端使用用户名跟密码请求登录
  2. 服务端收到请求,去验证用户名与密码
  3. 验证成功后,服务端会签发一个Token, 再把这个Token发送给客户端
  4. 客户端收到Token以后可以把它存储起来,比如放在Cookie里或者LocalStorage里
  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的Token
  6. 服务端收到请求,然后去验证客户端请求里面带着的Token,如果验证成功,就向客户端返回请求的数据

image.png

JWT技术

JWT,全称是Json Web Token, 是JSON风格轻量级的授权和身份认证规范,可实现无状态、分布式的Web应用授权

  • jWT的原理:

服务器认证以后,生成一个JSON对象,发回给用户,用户再发回这个JSON对象,客户端收到服务器返回的JWT ,可以储存在Cookie里面,也可以储存在localStorage。此后,客户端每次与服务器通信,都要带上这个JWT。可以把它放在Cookie里面自动发送,但是这样不能跨域,所以更好的做法是放在HTTP请求的头信息Authorization字段里面。

image.png

  • JWT实现
  1. 安装npm i jsonwebtoken

  2. 封装生成和认证token代码

const jwt = require('jsonwebtoken');
const Token = {
    encrypt:function(data) { //data加密数据,token-secret, 秘钥,time过期时间1天
    return jwt.sign(data, 'token-secret',{expiresIn:1000*60*60*24})
},
decrypt:function(token) {
    try {
        let data = jwt.verify(token, 'token-secret');
        return 
        token:true,
        id:data.id
    };
} catch (e) {
    return {
        token:false,
        data:e
    }
}
module exports = Token;
  1. 拦截所有请求进行认证
//捕获所有请求,统一认证
app.all('/*', (req, res, next) => {
    // 过滤不需要认证的接口
    let arr = ['/api/users/register', '/api/users/login', '/api/users/logout']
    if (arr.indexOf(req.url) !== -1) {
        next() //放行
        return
    }
    // 客户端将token置入authorization头部,请求接口时发送给服务端
    let TokenData = JwtToken.decrypt(req.headers.authorization)  //认证token
    if (!TokenData.token) {
        res.send({
            resultCode: -1,
            resultInfo: 'token无效',
        })
    } else {
        next()
    }
})
  1. 前端认证接口设置头
funcation loadUserList(pageNo) {
    let user = localStorage.getItem('USER')
    user = JSON.parse(user)
    // axios.defaults.headers.common['Authorization'] = user.token;
    axios({
        method: 'get',
        url: 'http://localhost:3000/api/vistor/list',
        //axios库get请求:parmas传参
        //axios库post请求: data传参
        headers:{
            authorization:user.token, //设置token认证头authorization
        },
        params:{
            pageNo
        }
    }).then(response => {
        let data = response.data
        if (data.resultCode == 1) {
            let result = data.resultInfo //用户列表数据
            showUserList(result)
        }else{
            alert(data.resultInfo)
        }
    })
}

axios简单封装与拦截器使用request.js

/**
 * 封装axios实例
 * 1.引入axios库
 *     axios() 默认axios实例,没有拦截器
 * 2.自己封装axios, 定义拦截器
 */
const myAxios = axios.create({
    baseURL: 'http://10.7.162.73:3000',
    timeout: 2000, //设置请求超时时间
})

// 定义拦截器
myAxios.interceptors.request.use(
    config => {
        // 设置token到authorization头部
	let token = Cookies.get('TOKEN')
	if (token) {
            config.headers.common['authorization'] = token
	}
        return config
    },
    error => {
	// 对请求错误做些什么
	return Promise.reject(error)
    }
)