三、Sails 中使用Jwt进行身份认证

article/2025/9/14 4:32:07

文章目录

  • Jwt 概述
    • 为什么要用Jwt
    • Jwt原理
  • Jwt认证
    • 安装 Jwt 库
    • 登录Api
      • Verify Signature
      • 过期时间
      • Nodejs 单线程易崩问题
    • 验证程序
    • 修改配置
      • 积极策略
      • 消极策略
      • 多重验证
  • Jwt 测试
    • 正常登录
    • 过期或错误密钥测试

Jwt 概述

由于我们是完全前后端分离的开发模式,我们的后端对前端提供Api,这个时候Api就会暴露出来,有些Api是包含敏感信息的。出于安全考虑的设计,肯定不允许任何人都可以访问这样的Api,这个时候就需要对Api的请求(request)进行身份认证(Authorization)。这种情况我们可以采用Jwt(Json Web Token)来完成这个事情。

为什么要用Jwt

身份认证还有一个可选项是采用Session技术,采用Jwt是因为它更适合前后端分离的开发模式。大致有几点原因:

  • Jwt中的token存储在客户端。完全无状态,可扩展。我们的负载均衡器可以将用户传递到任意服务器,因为在任何地方都没有状态或会话信息。
  • Session存储在服务端,日后后端采用负载均衡自动选择服务器的时候无法进行同步认证。
  • Session因为需要服务端存储,一般都要定期释放,如果要做类似“30天内记住密码”这种操作,那就会在服务器上面占用比较大的资源(30天内不能释放)。
  • Session 对CSRF的防御显然不如token。

Jwt原理

你可以简单的把Jwt理解成一种加解密技术。它把待加密信息分成三个部分:

  • Header 头部包含加密算法和toke类型
  • Payload 负载包含要加密的数据
  • Verify Signature 签名是我们可以保存在服务端的一个key字符串

构成这三个部分的信息经过Jwt加密成一个字符串,类似这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

我们的前端通过输入用户名+密码的方式给后端来实现登录,后端验证通过后把用户信息(一般是剔除掉密码的)和服务器的签名加密成一个字符串作为令牌(token)返回给前端。前端保存这个令牌,要访问敏感信息的时候发送给后端验证该token,如果签名是对的,并且token里面的用户信息也是对的,那我们就给予放行,否则就给予阻止。
关于Jwt的更多信息,https://jwt.io网站上有更详细的介绍,还有提供在线加解密的测试功能。
在这里插入图片描述

Jwt认证

安装 Jwt 库

在终端运行:

npm install jsonwebtoken --save

登录Api

安装Jwt之后,我们可以设计用户登录动作,我们再UserControllers控制器里面,添加函数login实现登录动作,代码如下:

export async function login(req: Api.SailsRequest, res: Api.Response): Promise<any> {let email = req.body.email, password = req.body.password;if (!(email && password)) { return res.serverError('email或password出现空值,请检查。') }//获取sails数据模型里面的user并且转换为UserModel.UserInstance类型let User = <UserModel.UserInstance>sails.models.user;try {User = await User.findOne({ email: req.body.email }).decrypt();if (!User) return res.status(401).send(`找不到email为:${req.body.email}的用户。`);if (User.password !== password) return res.status(401).send(`用户密码错误。`);let token = jwt.sign(User.toJSON(),//需要调用toJSON转为简单对象(plain object)并去除密码,不能使用包含function的对象sails.config.models.dataEncryptionKeys.default,//sails.config.models.dataEncryptionKeys.default 采用config/models里面的数据加密密钥,避免多个密钥设置{ expiresIn: '7d' }//expiresIn 解释 1h:1小时 1m:1分钟 1s:1秒 1d:1天 100:100毫秒 详见:https://github.com/vercel/ms);return res.send(token);} catch (error) {return res.serverError(error);}
}

Verify Signature

前面我们知道Jwt的Payload就是我们需要保存的数据,这个通过jwt.sign函数的第一个参数Uset.toJSON()获取,需要注意的是验证的签名需要保持在服务器,Sails里面本来就有对设置为encrypt的字段进行加密的功能,这个加密也是需要提供私钥的,我们可以通过config/model.js里面的dataEncryptionKeys进行设置,如下:

module.exports.models = {dataEncryptionKeys: {default: '4lB56JWieHhJISbwG0r+Y9MlPLEyTREu+y+V4ViPasA='},
}

为了避免后端维护多个密钥,在Jwt中我们可以采用同一个密钥。因此我们再源代码里面传入sails.config.models.dataEncryptionKeys.default作为Jwt的验证签名

过期时间

Jwt的过期时间采用的是https://github.com/vercel/ms这个库里面的时间描述,简单的理解就是d,h,m,s,分别代表天,分钟,小时和秒,如果是纯数字那就是毫秒为单位,其它表示方式可以参考该网站Readme

Nodejs 单线程易崩问题

我们采用Nodejs作为后端开发,常常会遇到Nodejs单线程迷思。实际上就是比较害怕线程安全问题,那么我们一开始Coding的时候就要紧绷这根弦,时刻注意开发中要及时采用try/catch来捕捉代码错误,防止因为我们没有捕获到的Error导致服务器卡死(uncaughtException die) 。

还有一些错误是从Node底层抛出的,有些异常 try/catch和uncaughtException都无法捕获。针对这种情况,行业内还提供forever这类守护进程的选项,让NodeJS遭遇异常崩溃以后能马上复活。 如果有需要可以安装使用。npm install forever -g

验证程序

用户登录(login)之后就拥有了token,访问端需要有可以对token进行验证的程序,我们在api/policies里面添加authenticated.ts,代码如下:

import Api from "typing/Api";
import UserModel from "typing/UserModel";
var jwt = require("jsonwebtoken");
declare var  sails:any;
async function authenticated(req: Api.SailsRequest, res: Api.Response, next: Function): Promise<any> {var bearerToken;var bearerHeader = req.headers['authorization'];if (!bearerHeader ) return res.status(403).send('您没有权限访问本页面');var bearer = bearerHeader.split(" ");if(bearer.length<2) return res.status(401).send('authorization格式错误');if (bearer[0] !== "Bearer") return res.status(401).send('authorization应该以Bearer为开头');bearerToken=bearer[1];try {var decoded = await jwt.verify(bearerToken, sails.config.models.dataEncryptionKeys.default);    let User = <UserModel.UserInstance>sails.models.user;    User=await User.findOne({ id: decoded.id });//进一步查找用户信息    if(!User) return res.status(403).send('找不到用户信息');req.user=User;    next();//放行(安检通过,执行next函数)return true;} catch(err:any) {if(err.name=='TokenExpiredError'){return res.status(403).send('登录超期,请重新登录后再试');}return res.status(401).send(err);}  
}
export = authenticated

本程序先解析request的请求头(header),如果没有authorization直接返回403,然后在解析authorization里面的Bearer,这种做法是行业内的通用做法,我们依例而做有利于我们程序通用性。验证的时候依然获取sails.config的dataEncryptionKeys作为签名,如果前端传来的签名不对,验证就不用通过,这种错误我们直接通过try/catch抛出去给前端即可。

修改配置

由于并不是所有api控制器里面的action都是需要身份验证的,比如login就不能进行验证,因为这个就是给用户登录的,用户登录前是不可能有token的。这个时候我们需要通过某个应用拦截器把api请求拦截住,检查看看有没有合格的身份验证,再决定是否放行(就像机场的安检),关于这样的拦截器Sails的机制是通过config配置hook来实现。在安全策略上面,我们可以通过config/policies.js中,设置需要验证用户登录的方法(controller中的action)来实现。修改改文件如下:

积极策略

module.exports.policies = {UserController: {retrieve: 'authenticated'}
};

以上采用积极设置策略,设置UserController中的retrieve动作(UserController里面的retrieve方法)需要验证,验证的代码为authenticated (sails会到api/policies文件夹里面按照文件名称去找对应的程序)。其它没有设置的控制器里面的Action都是不需要进行验证的。
采用积极策略的验证方法,还需要考虑sails的blueprint API(蓝图),因为蓝图api是默认是隐藏的,不需要再config/routes.js里面列出来的,如果我们采用蓝图api,我们还需要一样对用到的api进行策略设置(采用消极设置的方式就不需要考虑这个),关于蓝图api我们后面还会再讲。

消极策略

还有一种设置测试是先把所有控制器里面的动作都设置为需要验证,除了某些控制器的某些Action,比如:以下设置为除了login登录动作之外都需要身份验证

module.exports.policies = {'*': 'authenticated', 'UserController': {'login': true    }
};

多重验证

有一些Api动作是需要多重验证的,比如需要验证登录,并且还需要是指定区域的用户才能访问,这样的验证可以设置如下:

'UserController': {'getEncryptedData': ['isLoggedIn', 'isInValidRegion']}

Jwt 测试

正常登录

运行node app.js之后,打开postman,根据大家在数据库中创建的用户信息,测试用户登录Api
在这里插入图片描述
把返回的token复制起来,postman中新开一个窗口,测试userController里面的retrieve控制器,不输入token的时候是这样的:
在这里插入图片描述
在Authorizaiton里面输入token是这样的:
在这里插入图片描述
这个时候,我们如果查看postman的请求,可以看到类似如下代码:可以看到请求的header里面是有token的,并且以Bearer开头

var config = {method: 'post',url: 'http://localhost:1898/api/userRetrieve',headers: { 'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjcmVhdGVkQXQiOjE2Njg4NDYyMzE2MzcsInVwZGF0ZWRBdCI6MTY2ODg0NjIzMTYzNywiaWQiOjEsImVtYWlsIjoienpjYWlzbTlAMTk5LmNvbSIsIm5pY2tuYW1lIjoiIiwiaWF0IjoxNjY5MjE0MzgzLCJleHAiOjE2Njk4MTkxODN9.ZqBXznUz4uZKOz1J7V8u0f_t9ibwh1YDtnTtpKjQpNk', 'Cookie': 'sails.sid=s%3A3AVeBjcS3gKYQ60SyqsuQVsmVTaj6tD1.RiFrw%2FEEJwOjoWnIGsKIJUqbHTXWLIlgkTGpzgVMpFU'},data : data
};axios(config)
.then(function (response) {console.log(JSON.stringify(response.data));
})

过期或错误密钥测试

可以到jwt.io上面复制一段非服务器密钥加密过的token进行测试,Api返回invalid signature 。
也可以修改源代码里面的过期时间,做一个过期时间比较短的token出来测试。或是把我们加密过的token粘贴到jwt.io中,查看解密情况。这些操作将有助于提高您对jwt加密的认识。

通过测试,我们可以找出各种验证不通过的时候jwt捕获的错误消息中的name,然后完善验证代码中验证不通过的提示信息。


http://chatgpt.dhexx.cn/article/jnlEsYlf.shtml

相关文章

Sails基础之Controller层

通过前面的使用&#xff0c;我们可以看出Sails中MVC的结构更倾向于MVP的概念&#xff0c;Presenter在Sails中被称之为Actions&#xff1a; They often act as a middleman between your models and views. Controller层这个结构上的变化是Sails v1.0中新提出的方案&#xff0c;…

二、 在Sails中使用Typescript

文章目录 Typescript 基础Typescript 安装TypeScript 问题最简单的改造 Sails重定义Waterline&#xff08;Orm&#xff09; 重写ModelsTypescript 重写控制器User Model的进一步优化前后端约定 路径别名tsconfig.jsonmodule-alias安装使用 Jest测试 Typescript 基础 Typescrip…

四、Sails项目的Api文档——集成Swagger解决方案

文章目录 Api的迷思SwaggerSwagger概述在Sails中集成Swagger安装Swagger 生成设置生成的内容SwaggerUI Assets和.tmpBlueprint 蓝图Blueprint是什么Blueprint 配置local.js 进一步控制Swagger输出路由过滤路由的Swagger配置进一步优化Authorization Api的迷思 我们都知道写代码…

sails mysql_Sails+MVC+Mysql+Node+学习笔记一

项目构建 安装Node就不多说了&#xff0c; 1.sails安装与项目新建运行 npm install sails -g//全局安装 sails new project-name//新建项目 cd project-name //进入刚才新建项目的目录 sails lift //运行项目&#xff0c;运行原理也是直接在项目目录路径下使用node app.js npm …

Sails.js自动化Api实践与测试

开发中为了快速交互数据库&#xff0c;于是需要一个能便捷搭建api的平台。于是学习了一下sails.js框架。本次实践是一次摸索&#xff0c;使用了winston日志记录&#xff0c;supertest单元测试&#xff0c;mongo数据库&#xff0c;hashids哈希值解密。 模块: winstonsupertestmo…

五、解读Sails之Waterline源代码

文章目录 sql调试代码跟踪package.json启动调试Auto-Migrating备份原始数据删除所有表再重建回写备份数据 加密库 encrypted-attraes-256-gcm算法encrypted-att 的使用密钥 sql转义 sqlstring日期处理三种方式比较mariaDB&#xff08;或my-sql&#xff09;中的日期时间string 对…

一、Sails基础操作

本篇目录 Sails 安装App结构修改端口跨域问题第一个Api控制器用Postman 做Api调试MySql命令行操作MySql8.0版本加密问题 Sails 操作Mysql创建第一个model实现一个model的增删改查 Sails 安装 Sailsjs提供安装脚手架&#xff0c;使用之前可以先安装Sailjs npm install sails -…

sails

sails介绍 node.js的MVC框架&#xff0c;完全继承Express&socket.io的一些API 使用 全局安装 npm install -g sails创建项目 sails new 项目名称选2 选2 启动项目 sails liftsails框架目录介绍 api MVC结构项目代码目录controller层controller层尽量只做数据封装&…

Sails基础之Models层的config/datastores配置

配置与使用 Sails提供并支持多种Models层的存储&#xff08;https://sailsjs.com/documentation/concepts/extending-sails/adapters/available-adapters&#xff09;&#xff0c; 使用时需要在应用程序项目下安装对应的adapter并且在config/datastores或config/env/productio…

Sails的简单学习

这里贴出Sails的官方 一.Sails的简单介绍 官网上说&#xff1a; The web framework of your dreams.你梦想中的web框架。 Sails让创建自定义、企业级的Node.js应用的工作变得简单。它模拟了大家熟悉的诸如Ruby on Rails这种框架的MVC设置模式&#xff0c;但是也拥有满足现代…

什么是Sails

Sails的关键字 Realtime MVC Framework for Node.js Node.js Sails采用纯粹的Node.js进行构建&#xff0c;你只需要掌握一门javascript编程语言就可以构建Sails应用程序&#xff08;Web程序&#xff09;&#xff1b; MVC Framework Sails提供了基于MVC结构组织Web程序的基础…

sublime插件anaconda的设置

在 python 编辑环境下&#xff0c;使用 anaconda 完成一些代码补全和提示 具体设置如下 {//由于Anaconda插件本身无法知道Python安装的路径&#xff0c;所以需要设置Python主程序的实际位置"python_interpreter": "../python.exe",//忽略各种空格不对, 超…

Sublime 插件安装

1、百度搜索 Sublime3&#xff0c;进入 Sublime3 官网下载安装文件 注意&#xff1a;不要走到 Sublime2 的官网去下载&#xff0c;也不要使用 Sublime 的其它中文汉化版本&#xff1b; 2、下载 github 的 Package Control 包&#xff0c;下载地址&#xff1a; https://githu…

Sublime插件安装

1.PackageControl 功能&#xff1a;安装包管理 简介&#xff1a;sublime插件控制台&#xff0c;提供添加、删除、禁用、查找插件等功能 使用&#xff1a;https://sublime.wbond.net/installation 安装方法&#xff1a; CTRL &#xff0c;出现控制台粘贴以下代码至控制台 …

解决sublime无法下载插件问题

解决sublime无法下载插件问题 最近遇到了无法在sublime下载插件的问题&#xff0c;解决方法如下。 首先下载一个文件&#xff0c;地址如下 https://pan.baidu.com/s/1OlC0q8MwiZ_cEbs56SIwzw&#xff0c;提取码为vef9 下载完成后将其解压 再放入sublime文件夹中 接着点开P…

mac sublime安装插件

sublime 安装插件 需要等待一会&#xff0c;在弹出的新窗口&#xff0c;输入要添加的插件的名称&#xff0c;选择确认就可以了 以 Pretty JSON 插件为例&#xff0c;在将json字符串粘贴到文件之后&#xff0c;使用&#xff1a; control command j 进行格式化 调用搜索栏 shi…

java开发sublime插件_开发者最常用的8款Sublime text 3插件

5. SublimeCodeIntel Sublime​Code​Intel 作为一个代码提示和补全插件&#xff0c;支持Javascript、Mason、XBL、XUL、RHTML、SCSS、python、HTML、Ruby、Python3、XML、Sass、XSLT、Django、HTML5、Perl、CSS、Twig、Less、Smarty、Node.js、Tcl、TemplateToolkit 和 PHP 等…

Sublime Text - SublimeREPL插件的配置

1. 菜单Preferences -> Browse Packages&#xff0c;打开安装组件所在的文件夹&#xff0c;进入文件夹Data\Packages\SublimeREPL\config\Python&#xff0c;打开文件Default.sublime-commands&#xff0c;复制如下代码 { "caption": "SublimeREPL: Pyth…

Sublime常用c语言插件

1. Alignment 按等号对齐&#xff0c;强迫症患者必备 Alignment&#xff1a;选中并按ctrlalta就可以使其按照等号对齐 2. 配色方案Enki或者earthbound 3.A file icon 文件图标 4.CoolFormat&#xff1a;C代码格式化 简单好用的代码格式化工具&#xff0c;相当于简化版的Astyl…

Salesforce开发工具Sublime插件(一)

Salesforce开发工具Sublime插件 1. 下载Sublime 3(这是最新) http://www.sublimetext.com/3 进行脑残试的安装方法,下一步即可. 2.装好后打开.exe 3.安装Package Control 这个东东是一个方便 Sublime text 管理插件的插件&#xff0c;这个强大&#xff0c;把它装上去了&#…