Redis-优缺点分析与适用场景-JWT-方案比较-Token-与 (redis的五种数据类型)
在选择JWT与Token+Redis方案时,系统的具体需求和设计目标将是决定性因素。这两种方案都有各自的优缺点,适用于不同的场景。
JWT方案
优点 无状态性:后端不需要存储Token,减轻了服务器负担。 自包含性:Token自带信息,减少了对数据库的频繁查询。 轻量级:Token轻便,适合分布式环境。 缺点 不可撤销性:一旦颁发,后端无法即时废除,可能存在安全隐患。 不支持即时失效:在一些场景中,需要实时失效Token的需求会有挑战。Token+Redis方案
优点 可控性:可主动设置Redis中Token的失效时间,灵活撤销Token。 可管理性:适用于需要即时失效的情景,有更好的权限管理。 高灵活性:可根据需要存储额外信息,支持更复杂的数据管理。 缺点 存储需求:需要占用更多的存储空间,因为Token需要存储在Redis中。 依赖性:需要额外的Redis服务,增加了系统复杂度和维护成本。选择建议
对实时性要求高的系统,比如需要立即禁用用户登录或即时失效的场景,Token+Redis方案更适合。 无需即时控制、无状态要求高的系统,JWT可能更简洁高效。对于解决缺点的方案
JWT方案可以通过黑名单机制(如Redis存储已失效的JWT)部分解决不可撤销性问题。 Token+Redis方案可以考虑优化存储结构,降低存储空间占用,同时建立更加高效的Token管理机制。总结
在设计阶段,需要权衡两者的优劣,根据系统需求、安全性和实时性来做出选择,并针对方案的缺陷提出相应的解决方案。来,科普一下JWT
1. JSON Web Token是什么
JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。
2. 什么时候你应该用JSON Web Tokens
下列场景中使用JSON Web Token是很有用的:
Authorization (授权) :这是使用JWT的最常见场景。一旦用户登录,后续每个请求都将包含JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是现在广泛使用的JWT的一个特性,因为它的开销很小,并且可以轻松地跨域使用。
Information Exchange (信息交换) : 对于安全的在各方之间传输信息而言,JSON Web Tokens无疑是一种很好的方式。因为JWTs可以被签名,例如,用公钥/私钥对,你可以确定发送人就是它们所说的那个人。另外,由于签名是使用头和有效负载计算的,您还可以验证内容没有被篡改。
3. JSON Web Token的结构是什么样的
JSON Web Token由三部分组成,它们之间用圆点(.)连接。这三部分分别是:
因此,一个典型的JWT看起来是这个样子的:
接下来,具体看一下每一部分:
header典型的由两部分组成:token的类型(“JWT”)和算法名称(比如:HMAC SHA256或者RSA等等)。
例如:
然后,用Base64对这个JSON编码就得到JWT的第一部分
Public claims : 可以随意定义。
下面是一个例子:
对payload进行Base64编码就得到JWT的第二部分
为了得到签名部分,你必须有编码过的header、编码过的payload、一个秘钥,签名算法是header中指定的那个,然对它们签名即可。
例如:
签名是用于验证消息在传递过程中有没有被更改,并且,对于使用私钥签名的token,它还可以验证JWT的发送方是否为它所称的发送方。
看一张官网的图就明白了:
4. JSON Web Tokens是如何工作的
在认证的时候,当用户用他们的凭证成功登录以后,一个JSON Web Token将会被返回。此后,token就是用户凭证了,你必须非常小心以防止出现安全问题。一般而言,你保存令牌的时候不应该超过你所需要它的时间。
无论何时用户想要访问受保护的路由或者资源的时候,用户代理(通常是浏览器)都应该带上JWT,典型的,通常放在Authorization header中,用Bearer schema。
header应该看起来是这样的:
服务器上的受保护的路由将会检查Authorization header中的JWT是否有效,如果有效,则用户可以访问受保护的资源。如果JWT包含足够多的必需的数据,那么就可以减少对某些操作的数据库查询的需要,尽管可能并不总是如此。
如果token是在授权头(Authorization header)中发送的,那么跨源资源共享(CORS)将不会成为问题,因为它不使用cookie。
下面这张图显示了如何获取JWT以及使用它来访问APIs或者资源:
5. 基于Token的身份认证 与 基于服务器的身份认证
5.1. 基于服务器的身份认证
在讨论基于Token的身份认证是如何工作的以及它的好处之前,我们先来看一下以前我们是怎么做的:
HTTP协议是无状态的,也就是说,如果我们已经认证了一个用户,那么他下一次请求的时候,服务器不知道我是谁,我们必须再次认证
传统的做法是将已经认证过的用户信息存储在服务器上,比如Session。用户下次请求的时候带着Session ID,然后服务器以此检查用户是否认证过。
这种基于服务器的身份认证方式存在一些问题:
Sessions :每次用户认证通过以后,服务器需要创建一条记录保存用户信息,通常是在内存中,随着认证通过的用户越来越多,服务器的在这里的开销就会越来越大。
Scalability : 由于Session是在内存中的,这就带来一些扩展性的问题。
CORS : 当我们想要扩展我们的应用,让我们的数据被多个移动设备使用时,我们必须考虑跨资源共享问题。当使用AJAX调用从另一个域名下获取资源时,我们可能会遇到禁止请求的问题。
CSRF : 用户很容易受到CSRF攻击。
5.2. JWT与Session的差异
相同点是,它们都是存储用户信息;然而,Session是在服务器端的,而JWT是在客户端的。
Session方式存储用户信息的最大问题在于要占用大量服务器内存,增加服务器的开销。
而JWT方式将用户状态分散到了客户端中,可以明显减轻服务端的内存压力。
Session的状态是存储在服务器端,客户端只有session id;而Token的状态是存储在客户端。
5.3. 基于Token的身份认证是如何工作的
基于Token的身份认证是无状态的,服务器或者Session中不会存储任何用户信息。
虽然这一实现可能会有所不同,但其主要流程如下:
注意:
5.4. 用Token的好处
无状态和可扩展性: Tokens存储在客户端。完全无状态,可扩展。我们的负载均衡器可以将用户传递到任意服务器,因为在任何地方都没有状态或会话信息。
安全: Token不是Cookie。(The token, not a cookie.)每次请求的时候Token都会被发送。而且,由于没有Cookie被发送,还有助于防止CSRF攻击。即使在你的实现中将token存储到客户端的Cookie中,这个Cookie也只是一种存储机制,而非身份认证机制。没有基于会话的信息可以操作,因为我们没有会话!
还有一点,token在一段时间以后会过期,这个时候用户需要重新登录。这有助于我们保持安全。还有一个概念叫token撤销,它允许我们根据相同的授权许可使特定的token甚至一组token无效。
5.5. JWT与OAuth的区别
写在最后:我为大家准备了一些适合于1-5年以上开发经验的java程序员面试涉及到的绝大部分面试题及答案做成了文档和学习笔记文件以及架构视频资料免费分享给大家(包括Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术资料),希望可以帮助到大家。
前后端常见的几种鉴权方式(小结)
最近在重构公司以前产品的前端代码,摈弃了以前的session-cookie鉴权方式,采用token鉴权,忙里偷闲觉得有必要对几种常见的鉴权方式整理一下。 目前我们常用的鉴权有四种: HTTP Basic Authentication session-cookie Token 验证 OAuth(开放授权)一 Basic Authentication 这种授权方式是浏览器遵守http协议实现的基本授权方式,HTTP协议进行通信的过程中,HTTP协议定义了基本认证认证允许HTTP服务器对客户端进行用户身份证的方法。 认证过程:1. 客户端向服务器请求数据,请求的内容可能是一个网页或者是一个ajax异步请求,此时,假设客户端尚未被验证,则客户端提供如下请求至服务器:Get / HTTP/1.0 2. 服务器向客户端发送验证请求代码401,(WWW-Authenticate: Basic realm=””这句话是关键,如果没有客户端不会弹出用户名和密码输入界面)服务器返回的数据大抵如下:HTTP/1.0 401 Unauthorised Server: SokEvo/1.0 WWW-Authenticate: Basic realm=”” Content-Type: text/html Content-Length: xxx3. 当符合http1.0或1.1规范的客户端(如IE,FIREFOX)收到401返回值时,将自动弹出一个登录窗口,要求用户输入用户名和密码。 4. 用户输入用户名和密码后,将用户名及密码以BASE64加密方式加密,并将密文放入前一条请求信息中,则客户端发送的第一条请求信息则变成如下内容:Get / HTTP/1.0 Authorization: Basic d2FuZzp3YW5n注:d2FuZzp3YW5n表示加密后的用户名及密码(用户名:密码 然后通过base64加密,加密过程是浏览器默认的行为,不需要我们人为加密,我们只需要输入用户名密码即可)5. 服务器收到上述请求信息后,将Authorization字段后的用户信息取出、解密,将解密后的用户名及密码与用户数据库进行比较验证,如用户名及密码正确,服务器则根据请求,将所请求资源发送给客户端效果:客户端未未认证的时候,会弹出用户名密码输入框,这个时候请求时属于pending状态,这个时候其实服务当用户输入用户名密码的时候客户端会再次发送带Authentication头的请求。 认证成功 express = require(express);let app = express(); ((__dirname+/public)); (/Authentication_base,function(req,res){ (:,) if(!){ ({ WWW-Authenticate:Basic realm=wang }); (401)(); }else{ let base64 = ( )[1]; let userPass = new Buffer(base64, base64)()(:); let user = userPass[0]; let pass = userPass[1]; if(user==wang&&pass=wang){ (OK); }else{ (401)(); } } }) (9090):<!DOCTYPE html><html> <head> <meta charset=UTF-8> <title>HTTP Basic Authentication</title> </head> <body> <div></div> <script src=js/></script> <script> $(function(){ send(./Authentication_base); }) var send = function(url){ $({ url : url, method : GET, }); } </script> </body></html>当然有登陆就有注销,我们会发现当我们认证成功后每次请求请求头都会带上Authentication及里面的内容,那么如何做到让这次登陆失效的?网上查了半天,目前最有效的方式就是在注销操作的时候,专门在服务器设置一个专门的注销账号,当接收到的Authentication信息为注销用户名密码的时候纠就带便注销成功了,而客户端在注销操作的时候,手动的的去修改请求头重的Authentication,将他设置未服务器默认的注销账号和密码。 通过上面的简单讲解 其实我们已经可以返现这种验证方式的缺陷加密方式简单,仅仅是base64加密,这种加密方式是可逆的。 同时在每个请求的头上都会附带上用户名和密码信息,这样在外网是很容易被嗅探器探测到的。 总结:正式因为这样,这种加密方式一般多被用在内部安全性要求不高的的系统上,只是相对的多,总的来说现在使用这种鉴权比较少了。 如果项目需要部署在公网上,这种方式不推荐,当然你也可以和SSL来加密传输,这样会好一点,这个如果我后面有时间来研究一下。 二-cookie第二种这个方式是利用服务器端的session(会话)和浏览器端的cookie来实现前后端的认证,由于http请求时是无状态的,服务器正常情况下是不知道当前请求之前有没有来过,这个时候我们如果要记录状态,就需要在服务器端创建一个会话(seesion),将同一个客户端的请求都维护在各自得会会话中,每当请求到达服务器端的时候,先去查一下该客户端有没有在服务器端创建seesion,如果有则已经认证成功了,否则就没有认证。 session-cookie认证主要分四步: 1,服务器在接受客户端首次访问时在服务器端创建seesion,然后保存seesion(我们可以将seesion保存在内存中,也可以保存在redis中,推荐使用后者),然后给这个session生成一个唯一的标识字符串,然后在响应头中种下这个唯一标识字符串。 2.签名。 这一步只是对sid进行加密处理,服务端会根据这个secret密钥进行解密。 (非必需步骤) 3.浏览器中收到请求响应的时候会解析响应头,然后将sid保存在本地cookie中,浏览器在下次http请求de 请求头中会带上该域名下的cookie信息, 4.服务器在接受客户端请求时会去解析请求头cookie中的sid,然后根据这个sid去找服务器端保存的该客户端的session,然后判断该请求是否合法。 (nodejs+express+seesion+redis)var express = require(express);var RedisStore = require(connect-redis)();var app = express();var secret = wang// 设置 ((secret));// 设置 (({ store: new RedisStore({ host: 127.0.0.1, port: 6379, db: session_db }), secret: secret}))(/, function(req, res) { var session = ; = || 0; var n = ++; (hello, session id: + + count: + n);});(9080);三 验证使用基于 Token 的身份验证方法,大概的流程是这样的:1. 客户端使用用户名跟密码请求登录 2. 服务端收到请求,去验证用户名与密码 3. 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端 4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里 5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token 6. 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据总的来说就是客户端在首次登陆以后,服务端再次接收http请求的时候,就只认token了,请求只要每次把token带上就行了,服务器端会拦截所有的请求,然后校验token的合法性,合法就放行,不合法就返回401(鉴权失败)。 乍的一看好像和前面的seesion-cookie有点像,seesion-cookie是通过seesionid来作为浏览器和服务端的链接桥梁,而token验证方式貌似是token来起到seesionid的角色。 其实这两者差别是很大的。 1. sessionid 他只是一个唯一标识的字符串,服务端是根据这个字符串,来查询在服务器端保持的seesion,这里面才保存着用户的登陆状态。 但是token本身就是一种登陆成功凭证,他是在登陆成功后根据某种规则生成的一种信息凭证,他里面本身就保存着用户的登陆状态。 服务器端只需要根据定义的规则校验这个token是否合法就行。 2. session-cookie是需要cookie配合的,居然要cookie,那么在http代理客户端的选择上就是只有浏览器了,因为只有浏览器才会去解析请求响应头里面的cookie,然后每次请求再默认带上该域名下的cookie。 但是我们知道http代理客户端不只有浏览器,还有原生APP等等,这个时候cookie是不起作用的,或者浏览器端是可以禁止cookie的(虽然可以,但是这基本上是属于吃饱没事干的人干的事)?,但是token 就不一样,他是登陆请求在登陆成功后再请求响应体中返回的信息,客户端在收到响应的时候,可以把他存在本地的cookie,storage,或者内存中,然后再下一次请求的请求头重带上这个token就行了。 简单点来说cookie-session机制他限制了客户端的类型,而token验证机制丰富了客户端类型。 3. 时效性。 session-cookie的sessionid实在登陆的时候生成的而且在登出事时一直不变的,在一定程度上安全就会低,而token是可以在一段时间内动态改变的。 4. 可扩展性。 token验证本身是比较灵活的,一是token的解决方案有许多,常用的是JWT,二来我们可以基于token验证机制,专门做一个鉴权服务,用它向多个服务的请求进行统一鉴权。 下面就拿最常用的JWT(JSON WEB TOKEN)来说: JWT是Auth0提出的通过对JSON进行加密签名来实现授权验证的方案,就是登陆成功后将相关信息组成json对象,然后对这个对象进行某中方式的加密,返回给客户端,客户端在下次请求时带上这个token,服务端再收到请求时校验token合法性,其实也就是在校验请求的合法性。 JWT对象通常由三部分构成:Headers: 包括类别(typ)、加密算法(alg) { alg: HS256, typ: JWT }Claims :包括需要传递的用户信息 { sub: , name: John Doe, admin: true }Signature: 根据alg算法与私有秘钥进行加密得到的签名字串, 这一段是最重要的敏感信息,只能在服务端解密;HMACSHA256( base64UrlEncode(Headers) + . + base64UrlEncode(Claims), SECREATE_KEY)编码之后的JWT看起来是这样的一串字符95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQnodejs+express+jwt-simple jwt = require(jwt-simple);let secret = wangyy;let time = 10; = { /* *检验token合法性 */ validate:function(req,res,next){ let token = ||[xssToken]; if(token){ let decodeToken = null; try { //防止假冒token解析__ decodeToken = (token,secret,HS256); } catch (err) { (401)(非法访问); return; } let exp = ; if(!exp){ (401)(非法访问); } let now = new Date()(); if(exp>(now+time*60*1000)){ ({code:002,errorMsg:授权超时}) } next(); }else{ (401)(非法访问); } }, /* 生成token*/ makeToken(){ let Token = null; let payload = { time:new Date()(), (time) } Token = (payload,secret,HS256) return Token; }, /*生成token过期时间*/ makeExp:function(time){ let stam = time; } } express = require(express); let app = express(); let bodyParser = require(body-parser); let auth = require(./lib/); let chalk = require(chalk); (()); (/login,function(req,res,next){ let Token = (); ({result:success,token:Token},200) });(*,[],function(req,res,next){ (success); }); (9999)上面只是一个简单的token生成和校验,如果有需要可以根据实际需要进行逻辑处理四(开放授权)OAuth(开放授权)是一个开放标准,允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方网站或分享他们数据的所有内容,为了保护用户数据的安全和隐私,第三方网站访问用户数据前都需要显式的向用户征求授权。 我们常见的提供OAuth认证服务的厂商有支付宝,QQ,微信。 OAuth协议又有1.0和2.0两个版本。 相比较1.0版,2.0版整个授权验证流程更简单更安全,也是目前最主要的用户身份验证和授权方式。 下面是一张auth2.0的流程图: 从图中我们可以看出,auth2.0流程分为六布(我们就以csdn登陆为例):第一步. 向用户请求授权,现在很多的网站在登陆的时候都有第三方登陆的入口,当我们点击等第三方入口时,第三方授权服务会引导我们进入第三方登陆授权页面。 通过第三方请求授权页面的浏览器地址栏地址可以看出,这里的地址里面的%是浏览器强制编码后的显示我们可以使用decodeURIComponent进行解码,解码后是这样:这个url地址我们可以看见Auth2.0常见的几个参数: response_type,返回类型 client_id,第三方应用id,由授权服务器(qq)在第三方应用提交时颁发给第三方应用。 redirect_uri,登陆成功重定向页面 oauth_provider,第三方授权提供方 state,由第三方应用给出的随机码 第二步. 返回用户凭证(code),并返回一个凭证(code),当用户点击授权并登陆后,授权服务器将生成一个用户凭证(code)。 这个用户凭证会附加在重定向的地址redirect_uri的后面第3步. 请求授权服务器授权:经过第二部获取code后后面的工作就可以交给后台去处理的,和用户的交互就结束了。 接下来我的需要获取Access Token,我们需要用他来向授权服务器获取用户信息等资源。 第三方应用后台通过第二步的凭证(code)向授权服务器请求Access Token,这时候需要以下几个信息: client_id 标识第三方应用的id,由授权服务器(Github)在第三方应用提交时颁发给第三方应用 client_secret 第三方应用和授权服务器之间的安全凭证,由授权服务器(Github)在第三方应用提交时颁发给第三方应用 code 第一步中返回的用户凭证redirect_uri 第一步生成用户凭证后跳转到第二步时的地址 state 由第三方应用给出的随机码 第四步. 授权服务器同意授权后,返回一个资源访问的凭证(Access Token)。 第五步. 第三方应用通过第四步的凭证(Access Token)向资源服务器请求相关资源。 第六步. 资源服务器验证凭证(Access Token)通过
免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。