当前位置: 首页 > 后端技术 > Node.js

深入理解token认证机制(token)

时间:2023-04-03 15:25:29 Node.js

之前的开发模式是基于MVC的,但是随着互联网行业的快速发展,逐渐演变为前后端分离。如果项目中需要登录,那么token就成为前后端的唯一凭证。Token是标志、标记的意思,在IT领域也叫token。在计算机认证中它表示令牌(临时),在词法分析中它表示令牌。它通常用作邀请和登录系统。其实通俗一点的token可以叫做密码。在传输某些数据之前,必须先检查密码。不同的数据操作授权不同的密码。例如USB1.1协议中定义了四种数据包:令牌包、数据包、握手包和特殊包。主机和USB设备之间的持续数据交换可以分为三个阶段。在第一阶段,主机发送令牌数据包。不同的令牌包有不同的内容(不同的密码),可以告诉设备做不同的工作。第二阶段第一阶段发送数据包,第三阶段设备返回握手包。在HTTP请求中使用不记名令牌来访问OAuth2.0保护的资源。拥有不记名令牌(“不记名”)的任何一方都可以使用它来访问相关资源(无需证明拥有加密密钥)。为防止滥用,需要保护不记名令牌在存储和传输过程中不被泄??露。OAuth允许客户端通过获取访问令牌直接访问资源,访问令牌在“OAuth2.0授权”框架“[RFC6749]中定义为”表示访问的字符串,而不是使用资源的凭据。当令牌被服务器允许时,客户端以某种方式向服务器发送请求,服务器将请求发送给客户端,客户端使用访问令牌访问资源服务器托管的受保护资源。本规范描述了当OAuth访问令牌是不记名令牌时如何发出受保护的资源请求。客户端只需要有token,可以通过任何方式传递token。客户端需要知道参数加密的密钥,只需要保存令牌即可。OAuth为客户端提供了一种代表资源所有者访问受保护资源的方法。在一般情况下,客户端在访问受保护资源之前,必须首先获得资源所有者的授权,然后用该授权换取访问令牌。访问令牌表示授权授予的范围、持续时间和其他属性。客户端通过向资源服务器出示访问令牌来访问受保护的资源。在某些情况下,客户端可以显式地将其凭据直接发送到服务器。+--------++----------------+||--(A)-授权请求->|资源||||业主|||<-(B)--授权授予---||||+----------------+||||+--------------+||--(C)--授权授予-->|授权||客户||服务器|||<-(D)-----访问令牌------||||+----------------+||||+----------------+||--(E)-----访问令牌------>|资源||||服务器|||<-(F)---受保护的资源---||+------++--------------+该方案Authorization头字段的语法如下[RFC2617]第2节中定义的Basic方案的使用请注意,与Basic一样,它不符合[RFC2617]第1.2节中定义的通用语法,但与为HTTP1.1[HTTP-auth]开发的通用身份验证框架兼容,尽管它不遵循那里列出的反映现有部署的首选做法。bearercredentials语法如下b64toke=1*(ALPHA/DIGIT/"-"/"."/"_"/"~"/"+"/"/")*"="credentials="Bearer"1*SPb64token客户端应使用具有承载HTTP授权方案的授权请求标头字段使用承载令牌发出经过身份验证的请求。资源服务器必须支持此方法。BearerToken的使用在InternetEngineeringTaskForce(IETF)的白皮书中有介绍,那么我们平时使用token时的姿势是否正确。token应该如何正确使用?从“axios”导入axios;axios.interceptors.request.use(config=>{if(store.state.token){config.headers.authorization=`Basic${store.state.token}`;}returnconfig;});根据白皮书,这是使用代币的正确姿势。朋友们,你们平时是这样使用token的吗?那么除了对前端有明确的使用规范外,服务端应该如何有效保护后端数据呢?白皮书中也提到了。根据OAuth2.0动态客户端注册协议,该规范定义了一种向授权服务器动态注册OAuth2.0客户端的机制。注册请求向授权服务器发送一组所需的客户端元数据值(令牌)。生成的注册响应返回要在授权服务器上使用的客户端标识符和为客户端注册的客户端元数据值。然后,客户端可以使用此注册信息与使用OAuth2.0协议的授权服务器进行通信。该规范还定义了一组通用的客户端元数据字段和值,供客户端在注册期间使用。为了让OAuth2.0[RFC6749]客户端使用OAuth2.0授权服务器,客户端需要特定信息来与服务器交互,包括该服务器上使用的OAuth2.0客户端标识符。本规范描述了如何通过向授权服务器动态注册OAuth2.0客户端来获取此信息。摘要动态客户端注册流程+--------(A)-InitialAccessToken(OPTIONAL)||+----(B)-软件声明(可选)||vv+----------++-------------+||--(C)-客户端注册请求-->|客户||客户或||报名||开发者|<-(D)-客户端信息响应---|端点|||或客户端错误响应+----------------++----------+图中显示的抽象OAuth2.0客户端动态注册流程描述了两者之间的交互客户端或开发人员以及本规范中定义的端点。此图未显示错误情况。此流程包括以下步骤。(可选)向客户端或开发人员发出初始访问令牌,允许访问客户端注册端点。向客户或开发人员颁发初始访问令牌的方法超出了本规范的范围。客户端或开发人员可以选择发布软件声明以与客户端注册端点一起使用。向客户或开发人员发布软件声明的方法超出了本规范的范围。客户端或开发人员使用客户端所需的注册元数据调用客户端注册端点,如果授权服务器需要,则可以选择包括来自(A)的初始访问令牌。授权服务器注册客户端并返回有关客户端注册的元数据、服务器上唯一的客户端标识符和一组客户端凭证,例如客户端密码(如果适用于此客户端)。RelationshipBetweenGrantTypeandResponseType中描述的GrantType和ResponseType值是部分正交的,因为它们指的是传递给OAuth协议中不同端点的参数。但是,它们是相关的,因为客户端可用的授权类型会影响客户端可以使用的响应类型,反之亦然。例如,包含授权代码的授权类型值暗示包含代码的响应类型值,因为这两个值都被定义为OAuth2.0授权代码授予的一部分。因此,支持这些字段的服务器应该采取措施确保客户端不能将自己注册到不一致的状态,例如,通过向不一致的注册请求返回无效的客户端元数据错误响应。下表列出了这两个字段之间的相关性。+--------------------------------------------+-------------------+|grant_types值包括:|响应类型|||值包括:|+--------------------------------------------+-------------------+|授权码|代码||隐含|令牌||密码|(无)||客户凭证|(无)||刷新令牌|(无)||urn:ietf:params:oauth:grant-type:saml2-bearer|(无)|+----------------------------------------------+--------------------+GrantTypeorResponseTypeExtensionsandprofilesofthisdocumentwhereparametersintroducenewvalues必须记录这两个参数之间的所有通信类型。如果任何人类可读的字段在没有语言标签的情况下发送,使用该字段的各方不得对字符串值的语言、字符集或脚本做出任何假设,并且字符串值必须显示在用户界面中作为使用的位置。为了促进互操作性,建议客户端和服务器使用不使用任何语言标记的人类可读字段以及任何特定于语言的字段,并且建议任何不使用语言标记的人类可读字段包含适当的各种系统上显示的值。例如,软件语句可以包含以下语句:{"software_id":"4NRB1-0XZABZI9E6-5SM3R","client_name":"ExampleStatement-basedClient","client_uri":"https://client.example.net/"}以下非标准示例JWT包含这些声明,并使用RS256进行了非对称签名(仅用于显示目的)。等到加密字符串如下。eyJhbGciOiJSUzI1NiJ9.eyJzb2Z0d2FyZV9pZCI6IjROUkIxLTBYWkFCWkk5RTYtNVNNM1IiLCJjbGllbnRfbmFtZSI6IkV4YW1wbGUgU3RhdGVtZW50LWJhc2VkIENsaWVudCIsImNsaWVudF91cmkiOiJodHRwczovL2NsaWVudC5leGFtcGxlLm5ldC8ifQ.GHfL4QNIrQwL18BSRdE595T9jbzqa06R9BT8w409x9oIcKaZo_mt15riEXHazdISUvDIZhtiyNrSHQ8K4TvqWxH6uJgcmoodZdPwmWRIEYbQDLqPNxREtYn05X3AR7ia4FRjQ2ojZjk5fJqJdQ-JcfxyhK-P8BAWBd6I2LLA77IG32xtbhxYfHX7VhuU5ProJO8uvu3Ayv4XRhLZJY4yKfmyjiiKiPNe-Ia4SMy_d_QSWxskU5XIQl5Sa2YRPMbDRXttm2TfnZM1xx70DoYi8g6czz-CPGRi4SW_S2RKHIJfIjoI3zTJ0Y2oe0_EJAiXbL6OyF9S5tKxDXV8JIndSA加密字符串由头,载荷以及密钥通过一系列的速算法生成,加密字符串与头,载荷以及密钥息息相关,一但加密字符串稍有改动,无法正确解析,无法验证。通过加密字符串向授权服务器注册客户端。授权服务器为这个客户端分配一个唯一的客户端标识符,可选的客户端秘密,并将请求中提供的元数据与发布的客户端标识符相关联。该请求包括在注册期间为客户端指定的任何客户端元数据参数。授权服务器可以为客户端元数据中缺失的任何项目提供默认值。使用内容类型application/json注册端点。HTTPEntityPayload是一个JSONDocument对象,由JSON和所有请求的客户端元数据值组成,作为该JSON对象的顶级成员。示例:constKoa=require("koa");constRouter=require("koa-router");constjwt=require("jsonwebtoken");constjwtAuth=require("koa-jwt");constsecret="这是个秘密”;//keyconstapp=newKoa();constrouter=newRouter();router.get('/api/login',async(ctx)=>{const{username,passwd}=ctx.query;if(username==="aaron"&&passwd=="123456"){consttoken=jwt.sign({data:{name:"Aaron",userId:"1"},//用户信息exp:Math.floor(Date.now()/1000)+60*60//过期时间},secret);ctx.body={code:200,token};}else{ctx.status=401;ctx.body={code:0,message:"Incorrectusernameandpassword"};}});router.get("/api/userinfo",jwtAuth({secret}),async(ctx)=>{//jwtAuthaccepted保护路由ctx.body={code:200,data:{name:"Aaron",age:18}}});app.use(router.routes());app.listen(3000);因为最后生成的token是经过base64加密的,有些内容是可以逆向的,所以不要在数据中加入数据的敏感信息。请注意。..