2021-07-12-带着问题看源码2-NodeRed的用户认证机制是怎样的
1. 几种常用的认证机制#
1.1. HTTP Basic Auth#
Basic Auth是开放平台的两种认证方式,简单点说明就是每次请求API时都提供用户的username和password。
- 优点:
- 使用非常简单,
- 开发和调试工作简单,
- 没有复杂的页面跳转逻辑和交互过程;
- 更利于发起方控制;
- 缺点:
- 安全性低,每次都需要传递用户名和密码,用户名和密码很大程度上存在被监听盗取的可能;一次密码盗用,会导致所有使用此密码的全部应用处于风险之中
- 同时应用本地还需要保存用户名和密码,在应用本身的安全性来说,也存在很大问题;
- 开放平台服务商出于自身安全性的考虑(第三方可以得到该服务商用户的账号密码,对于服务商来说是一种安全隐患),未来也会限制此认证方式(Twitter就计划在6月份停止Basic Auth的支持)
- 用户如果更改了用户名和密码,还需要重新进行密码校验的过程。
1.2. OAuth#
OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版。
OAuth在”客户端”与”服务提供商”之间,设置了一个授权层(authorization layer)。”客户端”不能直接登录”服务提供商”,只能登录授权层,以此将用户与客户端区分开来。”客户端”登录授权层所用的token(token),与用户的密码不同。用户可以在登录的时候,指定授权层token的权限范围和有效期。
“客户端”登录授权层以后,”服务提供商”根据token的权限范围和有效期,向”客户端”开放用户储存的资料。
客户端必须得到用户的授权(authorization grant),才能获得token(access token)。
主要流程如下:
)
2. NodeRed中的认证机制使用#
NodeRed使用 OAuth 2.0 实现认证
2.1. 基于用户名/密码凭据的身份验证#
要在编辑器和管理API上启用用户身份验证,在settings.js文件中取消adminAuth属性的注释:
1 | adminAuth: { |
users属性是一个user对象数组。这允许您定义多个用户,每个用户可以拥有不同的权限。
上面的示例配置定义了两个用户。一个叫admin的人可以在编辑器内做任何事情,并且有一个密码为password的密码。另一个叫george,他被赋予只读访问权限。
请注意,密码是使用bcrypt算法生成的。
2.2. 针对任何OAuth/OpenID提供者(如Twitter或GitHub)进行身份验证#
要使用外部身份验证源,Node-RED可以使用Passport提供的各种策略。
Node-RED认证模块可以用于Twitter和GitHub。他们总结了一些具体的策略细节,使其更易于使用。但它们也可以用作其他类似策略的身份验证模板。
下面的示例演示如何配置针对Twitter的身份验证,而不使用我们提供的auth模块。
1 | adminAuth: { |
2.3. 自定义用户身份验证#
除了将用户硬编码到设置文件中,还可以插入自定义代码对用户进行身份验证。这使得与现有的身份验证方案集成成为可能。
将以下内容保存到一个名为
/user-authentication.js的文件中 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41module.exports = {
type: "credentials",
users: function(username) {
return new Promise(function(resolve) {
// Do whatever work is needed to check username is a valid
// user.
if (valid) {
// Resolve with the user object. It must contain
// properties 'username' and 'permissions'
var user = { username: "admin", permissions: "*" };
resolve(user);
} else {
// Resolve with null to indicate this user does not exist
resolve(null);
}
});
},
authenticate: function(username,password) {
return new Promise(function(resolve) {
// Do whatever work is needed to validate the username/password
// combination.
if (valid) {
// Resolve with the user object. Equivalent to having
// called users(username);
var user = { username: "admin", permissions: "*" };
resolve(user);
} else {
// Resolve with null to indicate the username/password pair
// were not valid.
resolve(null);
}
});
},
default: function() {
return new Promise(function(resolve) {
// Resolve with the user object for the default user.
// If no default user exists, resolve with null.
resolve({anonymous: true, permissions:"read"});
});
}
}在settings.js中设置adminAuth属性来加载这个模块:
1
adminAuth: require("./user-authentication")
2.4. 自定义的身份验证token#
在某些情况下,您可能需要使用自己的身份验证token,而不使用Node-RED生成的身份验证token。例如:
- 您希望使用基于OAuth的用户身份验证,但是您还需要自动访问管理API,它不能执行OAuth要求的交互式身份验证步骤
- 您希望将Node-RED集成到现有系统中,其中用户已经登录,并且不希望他们在访问编辑器时再次登录
adminAuth可以包括一个token函数。如果对管理api的请求不包含Node-RED识别为自己的身份验证token,则将调用此函数。将请求中提供的token传递给它,它应该返回一个与经过身份验证的用户进行解析的承诺,如果token无效,则返回null。
1 | adminAuth: { |
默认情况下,它将使用授权http头,并期待一个Bearer类型token——只将token的值传递给函数。如果它不是Bearer类型token,则授权头的完整值将传递给函数,其中包含类型和值。
要使用不同的HTTP头,可以使用tokenHeader设置来确定使用哪个头:
1 | adminAuth: { |
2.5. 使用自定义token访问编辑器#
要在不提示登录的情况下使用自定义Token访问编辑器,请向URL添加?access_token=< access_token >。编辑器将在本地存储该Token,并将其用于所有未来的请求。
3. 功能实现的参与者#
3.1. oauth2orize(主要功能及在本模块中的意义)#
OAuth2orize 是 NodeJS 的授权服务器工具包。它提供了一套中间件, 这些中间件与 passport 身份验证策略和特定于应用程序的路由处理程序相结合, 可用于组装实现 OAuth 2.0 协议的服务器。
主要方法:
- oauth2orize.createServer
提供授权服务器 - server.exchange
授权码交换访问Token。用户名及密码验证通过后,第三方(浏览器)可以使用授权码换到访问Token,通过Token就可以访问服务器资源。
3.2. passport#
passport.js是Nodejs中的一个做登录验证的中间件,极其灵活和模块化,并且可与Express、Sails等Web框架无缝集成。passport模块本身不能做认证,所有的认证方法都以策略模式封装为插件,需要某种认证时将其添加到package.json即可。
主要方法:
- passport.use
提供策略及配置 - passport.authenticate
对请求进行身份验证并指定认证策略 - passport.initialize
在基于Connect或express的应用程序中,需要Passport. initialize()中间件来初始化Passport。 - passport.session
如果您的应用程序使用持久登录会话,还必须使用passport.session()中间件。
请注意,启用会话支持是完全可选的,尽管大多数应用程序都推荐启用会话支持。如果启用,请确保在passport.session()之前使用session(),以确保登录会话以正确的顺序恢复。
3.3. express-session#
session 的运作通过一个 session_id 来进行。session_id 通常是存放在客户端的 cookie 中,比如在 express 中,默认是 connect.sid 这个字段,当请求到来时,服务端检查 cookie 中保存的 session_id 并通过这个 session_id 与服务器端的 session data 关联起来,进行数据的保存和修改。
express 中操作 session 要用到 express-session (https://github.com/expressjs/session ) 这个模块,主要的方法就是session(options),其中 options 中包含可选参数,主要有:
- name: 设置 cookie 中,保存 session 的字段名称,默认为 connect.sid 。
- store: session 的存储方式,默认存放在内存中,也可以使用 redis,mongodb 等。express 生态中都有相应模块的支持。
- secret: 通过设置的 secret 字符串,来计算 hash 值并放在 cookie 中,使产生的 signedCookie 防篡改。
- cookie: 设置存放 session id 的 cookie 的相关选项,默认为
- (default: { path: ‘/‘, httpOnly: true, secure: false, maxAge: null })
- genid: 产生一个新的 session_id 时,所使用的函数, 默认使用 uid2 这个 npm 包。
- rolling: 每个请求都重新设置一个 cookie,默认为 false。
- resave: 即使 session 没有被修改,也保存 session 值,默认为 true。
3.4. passport-http-bearer#
Passport的HTTP Bearer认证策略。
这个模块允许您在Node.js应用程序中使用Bearer Token(由RFC 6750指定)验证HTTP请求。Bearer Token通常使用保护API端点,并且通常使用OAuth 2.0发布。
通过插入Passport,BearerToken支持可以轻松地集成到支持连接式中间件的任何应用程序或框架中,包括Express。
passport-oauth2-client-password 策略#
OAuth 2.0 Passport客户端密码认证策略。
这个模块允许您验证请求体中包含客户端凭据的请求,正如OAuth 2.0规范所定义的那样。这些凭据通常用于保护Token端点,并用作HTTP基本身份验证的替代方案。
4. 功能分阶段描述#
auth:packages/node_modules/@node-red/editor-api/lib/auth/index.js
auth_users:packages/node_modules/@node-red/editor-api/lib/auth/users.js
auth_tokens:packages/node_modules/@node-red/editor-api/lib/auth/tokens.js
auth_strategies:packages/node_modules/@node-red/editor-api/lib/auth/strategies.js
storage:packages/node_modules/@node-red/runtime/lib/storage/index.js
%% 配置 %%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#FFFFFF'}}}%% sequenceDiagram autonumber %%实现 title: NodeRed中的用户认证机制(settings=credentials) participant 其他 auth -->> auth: 配置passport认证策略 auth -->> auth: 创建 oauth2 认证服务器 auth -->> auth: 配置 oauth2 授权码交换访问Token处理 其他 -->> auth: 启动初始化流程init auth -->> auth_users: 启动初始化流程init,初始化 Users 模块 auth -->> auth_tokens: 启动初始化流程init,初始化 Tokens 模块 其他 -->> auth: 将 /auth/login 路径路由到 login 、 errorHandler 方法 其他 -->> auth: 将 /auth/token 路径路由到 ensureClientSecret 、 authenticateClient 、 getToken、 errorHandler 方法 其他 -->> auth: 将 /auth/revoke 路径路由到 needsPermission 、revoke、 errorHandler 方法 auth -->> auth: ... 其他 -->> auth: 用户登陆操作,调用login方法,根据不同的settings配置,返回显示界面 auth -->> auth: ... 其他 -->> auth: 用户输入用户名称和密码,进行认证 auth -->> auth_users: 验证客户端ID(node-red-editor)是否有效,auth_users 使用 oauth2-client-password 策略 auth -->> auth: ... auth -->> auth_strategies: 根据已配置的 oauth2 授权码交换访问Token方法,获取Token auth_strategies -->> auth_users : 用户认证 authenticate(判断用户是否为合法用户,验证用户名和密码) auth_users -->> auth_strategies: 返回用户信息信息 auth_strategies -->> auth_strategies: 判断用户权限, permissions.hasPermission auth_strategies -->> auth_strategies: 创建Token auth_strategies -->> auth_tokens : 创建会话信息,设置会话结束时间,做Token超时处理 auth_tokens -->> storage: 保存会话信息到文件(/home/freeman/.node-red/.sessions.json) auth -->> auth: ... 其他 -->> auth: 用户登陆后所有操作,调用 bearerStrategy 方法,判断请求所携带的Token是否有效,若无效则返回错误信息,禁止操作 auth -->> auth: ... 其他 -->> auth: 用户登出操作,调用 revoke 方法 auth -->> auth: ...
5. 功能使用场景#
存在于使用的各阶段(初始化、运行、结束),是开启用户验证后必需的功能。
6. 实现方式特点#
- 使用策略模式对算法封装
- 模块化使用第三方库,完成用户认证
- 可扩展实现定制的用户认证
2021-07-12-带着问题看源码2-NodeRed的用户认证机制是怎样的
https://blog.buqia.fun/2022/02/17/2021-07-12-带着问题看源码2-NodeRed的用户认证机制是怎样的/