登錄實現(xiàn)方案與實踐

1、cookie是什么
◆存儲在瀏覽器的一段字符串,最大5kb
◆每個域都可有一個cookie , 跨域不共享
◆格式如k1=v1; k2=v2; k3=v3; ( 可結(jié)構(gòu)化)

2、cookie會隨http請求傳遞給服務端
◆每次 http請求, cookie都會隨著傳遞到服務端
◆服務端可修改 cookie再返回給前端
◆默認, 跨域不可傳遞cookie
3、 服務端操作 cookie

// 服務端操作 cookie

const http = require('http')

const server = http.createServer((req, res) => {

    // 設置 cookie
    res.setHeader('Set-Cookie', 'c=200')

    // 獲取 cookie
    const cookieStr = req.headers.cookie
    console.log('cookie is ', cookieStr)

    // // 結(jié)構(gòu)化 cookie(概念很重要)
    // cookieStr: 'a=100; b=200' --> { a: '100', b: '200' }
    const cookieObj = {}
    cookieStr.split(';').forEach(cookieItemStr => {
        const arr = cookieItemStr.trim().split('=')
        const key = arr[0] // 'a'
        const val = arr[1] // '100'
        cookieObj[key] = val
    })
    console.log('cookie obj is', cookieObj)

    res.end('cookie test')
})

server.listen(3000)
console.log('server listening on 3000 port')

4、Koa2設置或者獲取cookie

// Koa2 操作 cookie

const Koa = require('koa')
const app = new Koa()

app.use(async (ctx) => {

    // 設置 cookie
    ctx.cookies.set('a', '500')

    // 獲取 cookie
    console.log('cookie is', ctx.cookies.get('a'))

    ctx.body = 'cookie test by Koa2'
    // // 結(jié)構(gòu)化,koa2 已經(jīng)做好了

})

app.listen(3000)

5、cookie如何用于登錄校驗
◆請求登錄接口,成功則設置cookie,如user=zhangsan
◆前端再請求其他接口,就會帶著上述cookie【同域下】
◆服務端判斷cookie有無 user=zhangsan,即可驗證
6、cookie和session
1、cookie不能暴露用戶名
◆上一節(jié), cookie中有 user = zhangsan
◆cookie 存放用戶信息明文,非常危險
◆解決方案:cookie存一個用戶標識,如userld=123

2、session是什么
◆cookie 存儲用戶標識,如userId
◆用戶信息則存儲到session中
◆session 即用戶信息的存儲,和cookie有對應關系
——————————————————————
// 模擬 session 它是一個全局對象,它的key就是用戶標識,它的value就是存儲的用戶信息
session簡單的小例子:

// Koa2 操作 cookie

const Koa = require('koa')
const app = new Koa()

// 模擬 session
const SESSION_DATA = {
    '123': {
        user: 'zhangsan',
        age: 20
    },
    '456': {
        user: 'lisi'
    },
    '789': {
        user: 'shuangyue'
    }
}

app.use(async (ctx) => {
    // 加入用戶登錄成功,服務端設置 cookie (userId ,不能泄露用戶信息)
    ctx.cookies.set('userId', '123')

    // 其他接口,獲取 cookie
    const userId = ctx.cookies.get('userId')
    const userInfo = SESSION_DATA[userId]
    userInfo.user // 用戶名

    ctx.body = 'cookie test by Koa2'
})

app.listen(3000)

7、Koa2實現(xiàn)登錄
1、安裝插件

koa-generic-session --save

2、在app.js文件中引入和配置

引入
const session = require('koa-generic-session')
配置
app.keys = ['wertwe^&&*UUI123123'] // 秘鑰
// 自定配置了 cookie 和 session
app.use(session({
  // 配置 cookie
  cookie: {
    path: '/', // cookie 在根目錄下有效
    httpOnly: true, // cookie 只允許服務端來操作
    maxAge: 24 * 60 * 60 * 1000 // cookie 的過期時間
  }
}))

定義路由:router/index.js

router.get('/session-test', async (ctx, next) => {
  // ctx.session
  if (ctx.session.viewcount == null) {
    // 用戶尚未訪問
    ctx.session.viewcount = 0
  }
  // 用戶已經(jīng)訪問過了
  ctx.session.viewcount++ // 遞增

  // 返回
  ctx.body = {
    title: 'session-test',
    viewcount: ctx.session.viewcount
  }
})

8、模擬登錄和驗證

// 模擬登錄
router.get('/login-mock', async (ctx, next) => {
  let str = ''
  const query = ctx.query // url 參數(shù),querystring
  if (query.username) {
    // 模擬登錄成功
    ctx.session.userInfo = {
      username: query.username
    }
    str = 'login ok'
  } else {
    // 模擬登錄失敗,不用處理 session
    str = 'login failed'
  }

  ctx.body = str
})

// 模擬登錄驗證
router.get('/login-check-mock', async (ctx, next) => {
  ctx.body = ctx.session.userInfo || {}
})

9、完善登錄功能,連接數(shù)據(jù)庫

// 登錄(對接數(shù)據(jù)庫的)
// 為了方便同域的測試,暫用 get 請求
router.get('/login', async (ctx, next) => {
  const { username, password } = ctx.query // get 請求
  // const { username, password } = ctx.request.body // post 請求

  // 查詢數(shù)據(jù)庫
  const user = await User.findOne({
    username,
    password
  })

  if (user != null) {
    // 登錄成功,設置 session
    ctx.session.userInfo = user // 所有的用戶信息
    // 返回
    ctx.body = {
      errno: 0,
      data: user
    }
    return
  }
  // 登錄失敗,不用操作 session
  ctx.body = {
    errno: -1,
    message: '用戶名或密碼錯誤'
  }
})

10、登錄驗證的中間件

// 登錄驗證的中間件

async function loginCheck (ctx, next) {
    const userInfo = ctx.session.userInfo
    if (userInfo && userInfo.username) {
        // 登錄驗證成功
        await next()
        return
    }
    // 登錄失敗
    ctx.body = {
        errno: -1,
        message: '請登錄'
    }
}

module.exports = loginCheck

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容