前端node Session和JWT鉴权登录怎么实现

    服务端渲染及session鉴权

    服务端渲染

    服务端渲染简单来说就是前端页面是由服务器通过字符串拼接动态生成的,客户端不需要额外通过Ajax请求参数,只需要做好渲染工作即可。

    优点

    • 前端耗时少,前端只需要请求一次接口就能将数据渲染出来,首屏加载速度变快。

    • 利于SEO,因为服务器端相应的是完整的html页面内容,利于爬虫获取信息。

    缺点

    • 占用服务器资源,请求过多会造成访问压力。

    • 不利于前后端分类,并且前端复杂度高时不利于开发。

    服务端身份验证Session原理

    对于服务端渲染,推荐使用Session认证机制,再次之前,先说明一下cookie

    前端node Session和JWT鉴权登录怎么实现

    比如你可以在baidu.com看到以下cookie:

    前端node Session和JWT鉴权登录怎么实现

    session的鉴权就是利用了cookie,用户调用登录接口,完成账号密码的校验之后,将用户信息或者其他校验信息生成为cookie字符串,返回给用户,同时将cookie存储在服务器内存,用户请求其他接口时,会在请求头自动将cookie发送给服务器,服务器会通过与服务器内存中的用户信息匹配,如果匹配成功,则返回客户端想要的内容,否则抛出错误提示客户端需要重新登录。大致流程图如下:

    前端node Session和JWT鉴权登录怎么实现

    实践操作

    接下来我们来进行实践操作,在此之前请预先执行 npm i express express-session,安装所需要的模块。

    index.js文件的代码如下:

    // 导入 express 模块const express = require('express')// 创建 express 的服务器实例const app = express()// 01:配置 Session 中间件const session = require('express-session')app.use(  session({    secret: 'heyyyyfx',//此处的secret密钥可以是任意字符串,是你自己制定的专属加密方案,此处笔者将以自己的名字为例    resave: false,//无需在意,但是要写上    saveUninitialized: true,//无需在意,但是要写上  }))// 托管静态页面,此处笔者代理了一个静态文件,文件内容下文可见。app.use(express.static('./pages'))// 解析 POST 提交过来的表单数据app.use(express.urlencoded({ extended: false }))// 登录的 API 接口app.post('/api/login', (req, res) => {  // 判断用户提交的登录信息是否正确,此处写死一个账号密码校验,在实际开发中肯定是需要数据库匹配。  if (req.body.username !== 'admin' || req.body.password !== '000000') {    return res.send({ status: 1, msg: '登录失败' })  }  // 02:请将登录成功后的用户信息,保存到 Session 中  // 注意:只有成功配置了 express-session 这个中间件之后,才能够通过 req 点出来 session 这个属性  req.session.user = req.body // 用户的信息,我们将用户的信息转换成cookie字符串返回给用户。  req.session.islogin = true // 用户的登录状态,也是我们鉴权的参考  res.send({ status: 0, msg: '登录成功' })})// 获取用户姓名的接口app.get('/api/username', (req, res) => {  // 03:请从 Session 中获取用户的名称,响应给客户端  if (!req.session.islogin) {//此处就进行了鉴权,看用户的cookie是否有我们之前发送给他的islogin字段。    return res.send({ status: 1, msg: 'fail' })  }  res.send({    status: 0,    msg: 'success',    username: req.session.user.username,  })})// 退出登录的接口app.post('/api/logout', (req, res) => {  // 04:清空 Session 信息  req.session.destroy()  res.send({    status: 0,    msg: '退出登录成功',  })})// 调用 app.listen 方法,指定端口号并启动web服务器app.listen(80, function () {  console.log('Express server running at http://127.0.0.1:80')})

    其他

    缺陷

    可以看到,Session机制需要cookie的配合才能实现,因此cookie的的缺点或特性也就会影响到Session鉴权,比如,cookie是默认不支持跨域的,当前端跨域请求后端接口时,需要做很多额外的配置,这也就是为什么Session推荐在服务端使用。

    关于跨域

    笔者在本文中说到的的跨域问题,指的是客户端和服务端二者的跨域,如果读者下载了源码,可以看到笔者是在app.js(index.js)中使用app.use(express.static('./pages'))进行了静态托管,以此来保证客户端和服务端都是locallhost:80,是同源的。感兴趣的读者可以尝试用live Sever来代理Index.html文件,看看效果如何,在此之前记得引入cors中间件支持跨域。

    想说的

    其实笔者在此只是简单讲解了Session鉴权的大致原理以及进行了简单的实现,在实际真实开发中,首先我们不建议将用户信息返回生成cookie字符串再返回给客户端,因为这是非常隐私的信息,其次要知道cookie是可以直接在客户端更改的,因此鉴权关键字段也是需要斟酌的,现实开发是非常严谨的,请读者在实际使用时秉承严谨的态度。

    JWT鉴权

    适用情况

    上文已经说到了,session会受到跨域的影响,因此在前后端分离开发以及存在跨域的情况下,我们推荐使用JWT鉴权。

    JWT鉴权原理

    JWT原理和Session大致相同,不同的点在于,JWT生成的Token字符串需要客户端手动存储在localStoragesessionStorage中。再次请求时,客户端需要将Token放在请求头的Authorization字段中。

    前端node Session和JWT鉴权登录怎么实现

    JWT

    jwt是Json Web Token的缩写,它的结构分为三个部分:header.payload.signature,两两之间用【.】分隔。

    前端node Session和JWT鉴权登录怎么实现

    header

    header是一个JSON结构,主要包含token的类型(即JWT),签名的算法

    {    "alg":"HS256",    "typ":"JWT"}

    payload

    payload也是JSON结构,它是存放有效信息的地方,JWT官方提供了一些官方字段,你也可以定义自己的私有字段,其中官方字段如下:

    • iss:签发人

    • exp:token过期时间

    • sub:主题

    • aud:受众

    • nbf:生效时间

    • iat:签发时间

    • jti:编号

    但是注意,payload是默认不加密的,因此建议自己定义的私有字段不要放入用户私密信息。

    signature

    它是用户自己定义的字段,用户要设计一个独一无二且保证不会外泄的密钥,通过下方算法生成签名,用于未来的身份验证。

     HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

    实践

    首先安装必要的npm包,执行以下指令:

    npm i body-parser cors express express-jwt jsonwebtoken,

    在index.js中写入以下内容:

    // 导入 express 模块const express = require('express')// 创建 express 的服务器实例const app = express()// 01:安装并导入 JWT 相关的两个包,分别是 jsonwebtoken 和 express-jwtconst jwt = require('jsonwebtoken')const expressJWT = require('express-jwt')// 允许跨域资源共享const cors = require('cors')app.use(cors())// 解析 post 表单数据的中间件const bodyParser = require('body-parser')app.use(bodyParser.urlencoded({ extended: false }))// 02:定义 secret 密钥,建议将密钥命名为 secretKeyconst secretKey = 'heyyyyfx'// 04:注册将 JWT 字符串解析还原成 JSON 对象的中间件// 注意:只要配置成功了 express-jwt 这个中间件,就可以把解析出来的用户信息,挂载到 req.user 属性上// unless指定哪些接口不需要访问权限,即白名单。app.use(expressJWT({ secret: secretKey }).unless({ path: [/^/api//] }))// 登录接口app.post('/api/login', function (req, res) {  // 将 req.body 请求体中的数据,转存为 userinfo 常量  const userinfo = req.body  // 登录失败  if (userinfo.username !== 'admin' || userinfo.password !== '000000') {    return res.send({      status: 400,      message: '登录失败!',    })  }  // 登录成功  // 03:在登录成功之后,调用 jwt.sign() 方法生成 JWT 字符串。并通过 token 属性发送给客户端  // 参数1:用户的信息对象  // 参数2:加密的秘钥  // 参数3:配置对象,可以配置当前 token 的有效期,本处设置的是30S  // 记住:千万不要把密码加密到 token 字符中  const tokenStr = jwt.sign({ username: userinfo.username }, secretKey, { expiresIn: '30s' })  res.send({    status: 200,    message: '登录成功!',    token: tokenStr, // 要发送给客户端的 token 字符串  })})// 这是一个有权限的 API 接口app.get('/admin/getinfo', function (req, res) {  // 05:使用 req.user 获取用户信息,并使用 data 属性将用户信息发送给客户端  console.log(req.user)  res.send({    status: 200,    message: '获取用户信息成功!',    data: req.user, // 要发送给客户端的用户信息  })})// 06:使用全局错误处理中间件,捕获解析 JWT 失败后产生的错误app.use((err, req, res, next) => {  // 这次错误是由 token 解析失败导致的  if (err.name === 'UnauthorizedError') {    return res.send({      status: 401,      message: '无效的token',    })  }  res.send({    status: 500,    message: '未知的错误',  })})// 调用 app.listen 方法,指定端口号并启动web服务器app.listen(8888, function () {  console.log('Express server running at http://127.0.0.1:8888')})

    开启node服务后,用postman进行测试,调用登录接口后,拿到返回的Token:

    前端node Session和JWT鉴权登录怎么实现

    随后调用获取用户信息接口,注意,该接口是需要权限的,我们需要在请求头中加入Authorization字段,值为Token,同时有个注意事项,Token值前需要加入Bearer关键字,用空格分隔,这是必要的操作。

    前端node Session和JWT鉴权登录怎么实现

    如果你操作的过慢,就会看到如下报错,这是因为我们的有效期只有30s。

    前端node Session和JWT鉴权登录怎么实现

    不妨再调用一次登录接口,同时迅速用新的Token请求用户信息接口,结果如下,说明成功。

    前端node Session和JWT鉴权登录怎么实现

    想说的

    Token有效期问题

    在本文中,我们是自己为Token设置了30s的有效期,但如果你用心观察国内外的网站,貌似没有出现用着用着就突然返回到登录界面让你突然重新登陆的,难道是因为他们的有效期设置的特别长?

    其实在真实开发中,Token的有效期往往不会用这种方式设置,大多数有效期是动态的,打个比方,只有当你在当前页面半小时之内没有任何请求之后,才会让你的Token自动失效,这种是怎样实现的?其实有很多种实现方案,笔者在此只举一种例子,读者可以先了解一下redis数据库。

    redis数据库及动态Token解决方案

    redis的优点在此不做过多说明,感兴趣的可以自行查阅,redis数据库提供了一个叫expire的命令,命令用于设置 key 的过期时间,key 过期后将不再可用。单位以秒计。

    我们可以以此为基础,当用户请求登录接口时,我们将Token返回给用户,同时我们将这个Token作为Key存储到数据库,Value为这个用户的个人信息或其他内容,并为这个key设置一个定时删除命令,当用户在有效期时,数据库将用户请求接口时携带的Token进行查询,看是否存在这个Token的key,当可以被查询时,说明有效期还在(因为过了有效期这个Token就会被删除,表中就无法查询到这个Token),同时再次对这个Key执行定时删除任务,达到覆盖上一次删除定时任务,延长有效期的作用,只有当没有接口请求后,删除任务执行,Token才会失效,以此来实现动态Token的目的,至于覆盖定时删除任务这个操作,因为是每一个操作相关的接口都要进行,因此不妨将它封装成全局中间件,避免在每个接口中都写下重复代码。

    “前端node Session和JWT鉴权登录怎么实现”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!

    文章标题:前端node Session和JWT鉴权登录怎么实现,发布者:亿速云,转载请注明出处:https://worktile.com/kb/p/27851

    (0)
    打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
    亿速云的头像亿速云认证作者
    上一篇 2022年9月21日 上午12:16
    下一篇 2022年9月21日 上午12:17

    相关推荐

    • HTML5导航标签指的是什么

      在HTML5中,nav标签是导航标签;nav的全称是navigation,意为导航,该标签定义导航链接的部分,用于表示HTML页面中的导航,该标签并不是所有的HTML文档都要使用,只是作为标注一个导航链接的区域。 本教程操作环境:windows10系统、HTML5版本、Dell G3电脑。 HTML…

      2022年8月31日
      65800
    • 怎么用Intellij IDEA创建web项目

      Idea创建web项目 1.打开idea,选择file->New->Project 2.点击Java,点击下一步. 3.修改项目名。 4. 右键项目,选择add framework support 5. 完成之后,项目结构变成了这样 6. 接下来,我们在WEB-INF下创建classes…

      2022年8月30日
      1.1K00
    • python中DataFrame数据合并merge()和concat()方法怎么用

      merge() 1.常规合并 ①方法1 指定一个参照列,以该列为准,合并其他列。 import pandas as pddf1 = pd.DataFrame({‘id’: [‘001’, ‘002’, ‘003’], ‘num1’: [120, 101, 104], ‘num2’: [110, 10…

      2022年9月21日
      1.8K00
    • MySQL的rollback实例分析

      本文主要介绍“MySQL的rollback实例分析”的相关知识,文中所提到的一些操作方法不仅实用性强,且操作简单、快捷,不仅能帮助大家取得一定工作成果,而且还能提升工作效率,如果感兴趣的话,请耐心阅读! 事务回滚 事务是关系型数据库里的执行单位,可以通过最后阶段控制选择提交或回滚。在各种无法保证完整…

      2022年6月27日
      66500
    • Word首页不显示页码怎么设置

      首页不显示页码设置方法: 1、首先打开word文档。 2、然后点击上面菜单栏中的“插入”。 3、之后去点击功能里面的“页码”。 4、最后先去选择当前的页码, 然后点击右侧的删除键即可。 到此,相信大家对“Word首页不显示页码怎么设置”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关…

      2022年8月31日
      1.2K00
    • 为什么要定位服务器

      服务器定位的必要性主要包括四个方面:1、确保数据安全性;2、提高服务器的可访问性;3、方便进行系统维护和升级;4、优化性能和资源利用率。 在这四个方面中,以数据安全性为例,定位服务器可以帮助组织制定有效的安全措施以保护关键数据。服务器通常保存着大量敏感信息,这就要求有实体和网络安全措施来防止未经授权…

      2024年4月23日
      4700
    • windows谷歌浏览器缓存位置在哪

      谷歌浏览器缓存在哪: 1、打开谷歌浏览器在搜索栏输入“Chrome:Version”查看保存文件的位置。 2、随后在我的电脑中找到路径: C:UsersAdministratorAppDataLocalGoogleChromeUser DataDefault。 谷歌浏览器更改位置教程: 1、浏览器默…

      2022年9月8日
      92300
    • mdf文件打开方法是什么

      mdf文件怎么开: 如果mdf是镜像文件,我们需要虚拟光驱进行加载,下载并安装Daemon Tools虚拟光驱软件,打开就行了。 如果mdf是数据库文件,我们需要使用SQLServer管理工具进行打开,打开后点击文件,选择导入连接,选择需要打开的mdf文件 1、找到要打开的数据库文件 2、该数据库文…

      2022年9月8日
      2.4K00
    • TypeScript中怎么定义变量及使用数据类型

      TypeScript定义变量 变量声明格式 我在前面强调过,在TypeScript中定义变量需要指定 标识符 的类型。 所以完整的声明格式如下: 声明了类型后TypeScript就会进行类型检测,声明的类型可以称之为类型注解; var/let/const 标识符: 数据类型 = 赋值; 比如我们声明…

      2022年8月31日
      1.4K00
    • Python如何安装及建立虚拟环境

      一、python安装 python安装以Python3.7.9版本为例,其他版本安装步骤一致。 Python官网 二、建立虚拟环境 win+r,打开dos窗口 查看python是否安装成功 安装virtualenv,安装命令: pip install virtualenv -i https://py…

      2022年9月6日
      72900
    注册PingCode 在线客服
    站长微信
    站长微信
    电话联系

    400-800-1024

    工作日9:30-21:00在线

    分享本页
    返回顶部