手机版

谈认证(推荐)

时间:2021-08-20 来源:互联网 编辑:宝哥软件园 浏览:6

身份验证是系统级项目开发中遇到的常见问题。作为前端,我们可能离认证还很远。一般来说,我们只是套用,对权威没有深刻的理解。

什么是认证?身份验证是指验证用户是否有权访问系统。传统的认证是通过密码来验证的。这种方法的前提是每个获得密码的用户都已经被授权。创建用户时,会为用户分配一个密码。用户的密码可以由管理员指定,也可以由用户自己申请。这种方法的弱点显而易见:一旦密码被盗或用户丢失,情况会非常麻烦,管理员需要再次修改用户的密码,在更改密码之前必须手动验证用户的合法身份。——节选自百度百科

以上简要说明了身份验证的概念,但它只是一个简单的身份验证,也是项目中最常见、最安全的形式。然而,我们仍然不知道如何进行后端身份验证。一般来说,对于后端,最常见的身份验证方式分为三种:

Session/Cookie Token或Jwt OAuth是浏览器遵守HTTP协议的基本授权模式。在http协议通信过程中,HTTP协议定义了基本认证允许HTTP服务器向客户端认证用户的方法。接下来,我们将逐一介绍这三种身份验证方法。

session/cookiebookie是一个非常具体的东西,指的是一种可以永久存储在浏览器中的数据,它只是浏览器实现的一种数据存储功能。Cookies由服务器生成并发送到浏览器。浏览器将KV中的cookie保存到某个目录下的文本文件中,下次请求同一网站时将cookie发送给服务器。由于客户端存在cookie,浏览器增加了一些限制,以保证cookie不会被恶意使用,也不会占用太多的磁盘空间,所以每个域的cookie数量是有限的。

Cookie.js

const Http=require(' Http ');const app=Http . CreateServer((req,RES)={ if(req . URL==='/fav icon . ico '){ return;} else { RES . setheader(' Set-Cookie ',' CX=segment fault ');RES . end(' hello cookie ');};});app . listen(3000);用node Cookie.js运行上面的代码,程序启动后访问http://localhost 33603000/可以看到hello cookie这个词,表示服务已经启动。如果您想查看我们设置的Cookie,首先查看网络中的响应头,您可以看到我们编写的Set-Cookie属性。当我们访问http://localhost:3000/,当浏览器收到Set-Cookie属性时,浏览器将遵循其内部协议。并将其cookies存储在其浏览器中,打开浏览器控制台,在Application中找到的Cookies中找到对应的域名,就可以看到我们设置的Cookies值。当在同一个域中时,当再次请求数据时,默认情况下浏览器会在请求中发送cookie,并将它们一起发送到后端。要验证上述语句,请刷新http://localhost:3000/页,您可以在控制台网络中的请求头中看到Cookie: cx=Segmentfault属性。由于它被发送到服务器,Cookie也可以在后端被接收。修改上面的例子:

const Http=require(' Http ');const app=Http . CreateServer((req,RES)={ if(req . URL==='/fav icon . ico '){ return;}else{ console.log('cookie ',req . headers . Cookie)RES . setheader(' Set-Cookie ',' CX=segment fault ');RES . end(' hello cookie ');};});app . listen(3000);接收访问时,可以接收cx=Segmentfault。如果这个Cookie现在是加密数据,它包含一些用户信息。前端和后端交互后,当客户端再次请求服务器时,服务器获取对应的Cookie并解密,对其中的用户信息进行认证。

服务器通过设置Cookie在响应头中设置一段加密数据。客户端收到相应的数据后,浏览器会将其存储起来。当客户端再次发送请求时,它将在请求头中携带现有的Cookie并将其发送给服务器。服务器解密数据以完成身份验证。由此可以得出结论,Cookie是服务器在客户服务中存储的状态标记,然后由客户端发送到服务器,由服务器进行分析。Cookie必须在使用中的同一个域中,这是MVC中常用的。

我已经谈论Cookie很长时间了,但是我没有提到任何关于Session的事情。然后我会介绍Session,字面意思是会话。这类似于和某人说话。你怎么知道是张三在和你说话,而不是李四?必须有一些特征(外观等。)对方这才表明自己是张三。会话也是类似的原理。服务器需要知道谁在向自己发送请求。为了进行这种区分,服务器应该为每个客户端分配一个不同的身份,然后每次客户端向服务器发送请求时,它都会带来这个身份,服务器就会知道请求来自谁。客户端有很多方法可以保存这个身份。对于浏览器客户端,默认情况下每个人都使用Cookie。

const Http=require(' Http ');let session={ };const app=Http . CreateServer((req,RES)={ const Session KeY=' Uid ';if(req . URL==='/fav icon . ico '){ return;} else { const Uid=ParSeint(Math . random()* 10e 10);const cookie=req . headers . cookie;if(cookie)cookie . indexof(session key)!==-1){ let _ Uid=cookie . split('=')[1];res.end(`${session[_uId]。名字}回来`);} else { RES . setheader(' Set-Cookie ',` $ { SessionKey }=$ { Uid } `);session[Uid]={ ' name ' : ' Aaron ' };RES . end(' hello cookie ');} };});app . listen(3000);Cookies在代码中以简单的方式解析,只是为了完成Dome。在实际项目中获取cookies要比这复杂得多。

会话/Cookie身份验证主要分为四个步骤:

当服务器接收到客户端的第一次访问时,它会在服务器端创建一个seesion,然后保存seesion(我们可以将seesion保存在内存或redis中,推荐后者),然后为这个会话生成一个唯一的标识字符串,然后将这个唯一的标识字符串植入响应头中。签名。这一步只加密sid,服务器会根据这个密钥解密。(可选步骤)当浏览器收到请求响应时,它将解析响应头,然后将sid保存在本地cookie中。当浏览器发出下一个http请求时,请求头会将cookie信息放在域名下。当服务器接受客户端请求时,会解析请求头cookie中的sid,然后根据sid找到服务器保存的客户端的会话,进而判断请求是否合法。

通过使用服务器端的会话和浏览器端的cookie来实现前端和后端的认证。由于http请求是无状态的,服务器通常不知道当前请求之前是否已经到来。此时,如果我们想要记录状态,我们需要在服务器端创建一个会话,并在自己的会话中维护同一个客户端的请求。每当请求到达服务器端时,首先检查客户端是否在服务器端创建了会话。如果是,则认证成功。

与redis结合使用:

const KOA=require(' KOA ');const session=require(' KOA-session ');const redis store=require(' KOA-redis ');const redis=require(' redis ');const wrapper=require(' co-redis ');const app=new KOA();const redisClient=redis . create client(6379,‘localhost’);const client=wrapper(redisClient);//类似于key app . keys=[' Aaron '];const SESSION _ CONFIG={//set SESSION key 3360 ' sid ',//最大有效期maxAge:8640000,//是否阻止js读取httpOnly:true,//cookie二级签名signed:true,//存储模式stro : redis store({ client })app . use(SESSION(SESSION _ CONFIG,app));app . use((CTX)={ redisclient . keys(' * ',(err,keys)={ keys . foreach(key={ redisclient . get(key),(err,val)={ console . log(val));});})})if(CTX . path==='/fav icon . ico ')返回;让n=CTX . session . count | | 0;CTX . session . count=n;Ctx.body=` ${n}次访问` });app . listen(3000);Session/Cookie虽然可以解决认证问题,但是会出现很大的问题,对服务器来说是一笔巨大的开销,严重限制了服务器的扩展能力。比如我用两台机器组成一个集群,小F通过机器A登录系统,那么sessionId就会保存在机器A上,如果小F的下一个请求转发给机器B呢?机器b没有小f的sessionId,有时候会用一个小技巧:session sticky,也就是把小f的请求一直卡在机器a上,但是不起作用。如果机器a挂起,它必须转到机器b。然后我们必须复制会话,并在两台机器之间移动会话Id。再好的服务器也经不起这种折腾。

Token或Jwt在计算机认证中表示token(临时),在词法分析中表示mark。一般用作邀请和登录系统。现在,前后端分离火热,Token蒸蒸日上。Token用于许多项目开发过程中。事实上,Token是一个字符串,通常用作身份验证凭据,最常用的使用场景是API身份验证。

客户端使用用户名和密码请求登录。服务器接收验证用户名和密码的请求。验证成功后,服务器将颁发一个令牌,然后将该令牌发送给客户端。收到令牌后,客户端本地存储它。例如,当客户端向服务器请求资源时,它需要获取服务器发出的令牌来接收请求,然后验证客户端请求中携带的令牌。如果验证成功,它将向客户端返回请求的数据。

示例:

前端

!DOCTYPE html html lang=' en ' hearta charset=' UTF-8 ' meta name=' viewport ' content=' width=device-width,initial-scale=1.0 ' meta http-equiv=' X-UA-Compatible ' content=' ie=edge ' script src=' http 3360https://cdn。jsdeliver。net/NPM/vue/dist/vue。js '/script script src=' http 3360https://unpkg .登陆/button button @click='loginOut '退出/button button @ click=' GetUserInfo '获取用户信息/button/div div button @ click=' logs=[]'清空日志/button /div ul li v-for='(item,index)of log ' : key=' index ' { item } }/Li/ul/divscriptaxios。默认值。baseURl=' http://localhost :3000 '//请求拦截axios。拦截器。请求。使用((config)={ const token=本地存储。getitem(' token ');if(token){ //判断是否存在令牌,如果存在的话//每次发起超文本传送协议请求时在头球中添加令牌//持有者是JWT的认证头部信息配置。标题['授权']='来人${token}` }返回配置;},错误=警报(错误));//响应拦截axios。拦截器。回应。使用((RES)={ app。日志。推送(JSON。字符串数据)返回RES},错误=警报(错误));const app=new Vue({ El : ' # app },data:{ username: ' ',passwrold: ' ',logs:[] },methods : { log in(){ let { username,passwrold }=thisaxios。post('/用户/登录/令牌',{用户名,密码}).然后((RES)={本地存储。setitem(' token ',res.data.token) }) },loginOut(){ axios。帖子('/用户/注销').然后((RES)={本地存储。移除项目(' token ')})},getUserInfo(){ axios。get('/user/get/user/info ').然后((RES)={控制台。log(RES)});} } })/脚本/正文/html后端:

const Koa=require(' Koa ');const jwt=require(' jsonwebtoken ');const jwtAuth=require(' KOA-jwt ');const Router=require(' KOA-Router ');//koa路由中间件const body解析器=require(' KOA-body解析器');const CORS=require(' KOA 2-CORS ');const app=new Koa();const Router=new Router();//密钥const secret="这是一个秘密";app。使用(BodyParser());app。使用(CORS());路由器。post('/user/log in/token ',(CTX)={ const { body }=CTX。请求;const { username }=body CTX . body={ code :1,message: '登陆成功,body:{ username },token : jwt。符号({ data : body,exp : path。楼层(日期。now()/1000)60 * 60,},secret)});router.post('/users/logout ',(CTX)={ const { body }=CTX。请求;ctx.body={ code:1,message: '退出成功} })路由器。get('/users/get/user/info ',jwtAuth({secret}),(ctx)={ //jwtAuth令牌参数控制台。原木(CTX。国家。用户。数据)CTX。body={代码:1,消息: '成功,数据: CTX。国家。用户。data } })应用程序。使用(路由器。routes());app。听(3000);上面代码用到了很多的依赖模块,最关键的的是jsonwebtoken和koa-jwt,这两个模块一个是用来对代币进行加密,一个是用来对数据进行解密的,同时在每次访问需要保护的路由的时候需要使用jwtAuth对其进行拦截处理,jwtAuth会根据其秘密进行数据解密,把解密的数据存放到ctx.state中,供用户读取。

有关智威汤逊广告公司相关请查看深入理解令牌认证机制详细的解释了其加密后数据代币的构成。

加密后的数据主要分为三个部分机密头部、载荷、数据如果我们想查看其加密前内容是什么样子的,可以通过base64对其没一部分进行解密。

机密头:声明加密规则,可以反向加载:数据信息,也就是我们需要加密的信息,可以反向验证:这部分是对前两部分使用哈希算法的总结,是不可逆的。在使用jsonwebtoken时,需要注意的是,由于加密信息可以反转,所以尽量不要将敏感信息存储在加密数据中,如用户密码、用户隐私信息等。(千万不要模仿Dome,这是错误的)如上所述,传递给前端的令牌一旦发生变化,就不可能只改变一个字母的情况。当服务器收到要解密的令牌时,它无法正确解密。这个令牌可以被篡改。如果你想篡改令牌,你必须有它的秘密,然后才能篡改和伪造它。

OAuthOAuth (oauth2.0)是一个开放标准,它允许用户授权第三方网站访问他们存储在其他服务提供商上的信息,而无需向第三方网站提供用户名和密码,也无需共享其数据的所有内容。为了保护用户数据的安全和隐私,第三方网站在访问用户数据之前需要明确要求用户授权。我们常见的OAuth认证服务提供商有支付宝、QQ、微信。

OAuth协议有两个版本:1.0和2.0。与1.0版本相比,2.0版本的整个授权验证过程更简单、更安全,也是目前最重要的用户认证和授权方式。

OAuth认证主要经历了以下步骤:

第三方应用程序存储资源所有者的凭据是未来使用所必需的,通常是明文密码。服务器需要支持密码身份验证,尽管密码身份验证存在固有的安全缺陷。第三方应用程序获取的资源所有者对受保护资源的访问权限过于宽泛,导致资源所有者对资源的使用期限或范围失去控制。资源所有者不能只撤销第三方的访问权限而不影响他人,只有通过更改第三方的密码,资源所有者才能单独撤销第三方的访问权限。对任何第三方应用程序的让步都会导致对最终用户的密码和受密码保护的所有数据的让步。简而言之,它是由第三方在用户授权下,通过访问平台的开放接口来获取用户相关信息。OAuth引入了授权链接来解决上述问题。当第三方应用程序请求访问受保护的资源时,资源服务器将在获得资源用户授权后向第三方应用程序发出访问令牌。访问令牌包含资源用户的授权访问范围、授权有效期等关键属性。第三方应用程序需要在后续的资源访问过程中持有令牌,直到用户自愿结束授权或令牌自动过期。

总结授权的方式很多,主要看我们的产品定位。如果我们的产品只用于企业,令牌和会话可以满足我们的需求。现在jwt认证方式更适合。

以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。

版权声明:谈认证(推荐)是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。