3种经常使用鉴权方法原理与实现

学生一枚,做为学习和总结。若是有哪些不对的地方,还请指教javascript

cookie

诞生

HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的链接就会关闭,再次交换数据须要创建新的链接。html

为解决这个问题,有了cookie出现vue

cookie介绍

Cookie是由服务器端生成,发送给User-Agent(通常是浏览器),(通知浏览器设置一下cookie),浏览器自动会将Cookie以进行保存(以key/value的形式)。当下次请求同一网站时也会自动发送该Cookie给服务器,即添加在请求头部。java

存放在浏览器端node

原理即代码实现

const http = require("http")
http.createServer((req, res) => {
    // 观察cookie是否存在 若是存在就打印cookie
    console.log('cookie:', req.headers.cookie)
    // 设置cookie
    res.setHeader('Set-Cookie', 'cookie=abc;')
    res.end('hello cookie!!')
}).listen(3000)
复制代码

结果展现

为何会有两次?

第一次 请求的时候 发现没有cookie,就进行了设置ios

第二次请求,发现有cookie了,就直接输出了git

session

  1. 基于cookie 实现,存放在服务端
  2. 里面只存一个cookieId,其余的保存在服务器中

代码即原理展现

// principle
const http = require("http")
const session = {} // 用来存放cookie
http.createServer((req, res) => {
    // 观察cookie存在
    console.log('cookie:', req.headers.cookie)
    const sessionKey = 'sid'
    const cookie = req.headers.cookie
    if (cookie && cookie.indexOf(sessionKey) > -1) { // 证实cookie 存在
        res.end('Come Back ')
        // 简略写法未必具备通用性
        const pattern = new RegExp(`${sessionKey}=([^;]+);?\s*`)  // 正则表达式对象 判断是否又sid = XX等
        console.log(pattern)
        const sid = pattern.exec(cookie)[1] // 检索字符串中指定的值。返回找到的值
        console.log('session:', sid, session, session[sid])
    } else {
        const sid = (Math.random() * 99999999).toFixed()
        // 设置cookie
        res.setHeader('Set-Cookie', `${sessionKey}=${sid};`)
        session[sid] = {name: 'oldWang'}
        res.end('Hello')
    }
    res.end('hello cookie!!')
}).listen(3000)
复制代码

分析

浏览器不存在cookie 的时候,走else,随机设置一个sid,(通常是本身设置,尽可能麻烦一点),而后 设置cookie, 在session集合中保存用户信息,(通常存到数据库里面), 最后返回结果github

第二次进入的时候,会走if ,进行取值判断。web

Token

使用缘由

  1. Session不足,服务器存在状态
  2. 不灵活,(cookie只存在于浏览器)

过程

  1. 客户端使用户名跟密码请求登陆
  2. 服务端收到请求,去验证用户名与密码
  3. 验证成功后,服务端会签发一个令牌(Token),再把这个 Token 发送给客户端
  4. 客户端收到 Token 之后能够把它存储起来,⽐好比放在 Cookie 里或者 Local Storage ⾥
  5. 客户端每次向服务端请求资源的时候须要带着服务端签发的 Token
  6. 服务端收到请求,而后去验证客户端请求里面带着的 Token,若是验证成功,就向客户端返回 请求的数据

例子实现

前台

<!DOCTYPE html>
<html lang="en">
<head>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <div><input v-model="username"/> <input v-model="password"/></div>
    <div>
        <button @click="login">登录</button>
        <button @click="logout">退出</button>
        <button @click="getUser" >获取用户</button>
    </div>
    <div>
        <button @click="logs=[]">清除页面</button>
    </div>  
    <ul>
        <li v-for="(log,idx) in logs" :key="idx"> {{ log }}</li>
    </ul>
</div>
<script> axios.defaults.baseURL = 'http://localhost:3000' axios.defaults.withCredentials = true axios.interceptors.request.use(config => { const token = window.localStorage.getItem("token"); if (token) { // 判断是否存在token,若是存在的话,则每一个http header都加上token // Bearer是JWT的认证头部信息 config.headers.common["Authorization"] = "Bearer " + token; } return config; }, err => { return Promise.reject(err); }); axios.interceptors.response.use(response => { app.logs.push(JSON.stringify(response.data)); return response; }, err => { app.logs.push(JSON.stringify(response.data)); return Promise.reject(err); }); var app = new Vue({ el: "#app", data: { username: "admin", password: "admin", logs: [] }, methods: { login: async function () { const res = await axios.post("/users/login-token", { username: this.username, password: this.password }); localStorage.setItem("token", res.data.token); }, logout: async function () { this.logs.push('退出登录') localStorage.removeItem("token"); }, getUser: async function () { await axios.get("/users/getUser-token"); } } }); </script>
</body>
</html>
复制代码

后台代码

const Koa = require('koa')
const router = require('koa-router')() // koa路由
const jwt = require("jsonwebtoken")
const jwtAuth = require("koa-jwt")
const secret = "it's a secret"
const cors = require('koa2-cors')
// https://www.jb51.net/article/135924.htm 跨域参考
const bodyParser = require('koa-bodyparser') // 不支持table,支持json
const static = require('koa-static')
const app = new Koa();

app.keys = ['some secret'];
app.use(cors({credentials: true})) // 解决跨域
app.use(static(__dirname + '/'));
app.use(bodyParser())
router.post("/users/login-token", async ctx => {
    const {body} = ctx.request;
    console.log(body)
    //登陆逻辑,略略
    // 设置session
    const userinfo = body.username;
    ctx.body = {
        message: "登陆成功", user: userinfo,
        // ⽣生成 token 返回给客户端
        token: jwt.sign({
            data: userinfo,
            // 设置 token 过时时间,一⼩小时后,秒为单位
            exp: Math.floor(Date.now() / 1000) + 60 * 60
        }, secret)
    };
})

router.get("/users/getUser-token", jwtAuth({secret}), async ctx => {
    // 验证经过,state.user
    console.log(ctx.state.user);
    //获取session
    ctx.body = {message: "获取数据成功", userinfo: ctx.state.user.data};
});

app.use(router.routes());
app.use(router.allowedMethods());
app.listen(3000);

复制代码

jsonwebtoken github正则表达式

相关文章
相关标签/搜索