认证方式
基于Cookie和Session的认证方式
基于Cookie和Session的认证是传统的Web应用认证机制。它依赖于HTTP协议无状态的特性,在客户端(浏览器)和服务器之间保持用户的状态。
工作原理
用户登录:用户通过输入用户名和密码来登录Web应用。
验证凭据:服务器验证用户提交的凭据。如果凭据有效,服务器将创建一个会话(Session),该会话包含用户的登录信息和其他必要的状态信息。
发送Cookie:服务器生成一个唯一的会话ID,并将其存储在会话存储中(如内存、数据库或其他存储系统)。然后,服务器通过设置HTTP响应中的Set-Cookie头部,将此会话ID发送回客户端,保存在Cookie中。
客户端存储Cookie:客户端(浏览器)接收到Cookie后,会将它保存起来,并在随后对同一服务器的每个请求中自动发送这个Cookie。
服务器识别用户:每当服务器收到来自客户端的请求时,它会查找请求中的Cookie,提取会话ID,并使用此ID查找存储的会话信息。如果找到会话,服务器就能知道是哪个用户发出的请求,并根据会话中保存的状态进行处理。
举例假设有一个简单的Web登录流程:
用户访问登录页面(/login),输入用户名和密码。
服务器验证用户凭据。如果凭据有效,服务器创建一个Session,生成一个会话ID,并将其作为Cookie发送回用户。
用户收到Cookie后,每次访问Web应用的其他页面时,都会在请求中携带这个Cookie。
服务器接收到请求,从Cookie中提取会话ID,查找对应的Session,并识别出用户,根据用户的权限显示相应的内容。
缺点
1.服务端需要存储Session,并且由于Session经常需要快速查找,通常存储再内存或内存数据库中,同时在线用户较多时需要占用大量的服务器资源。
2.当需要扩展时,创建Session的服务器可能不是验证Session的服务器,所以还需要将所有Session单独存储并共享。
3.在跨域环境下要进行兼容性处理。否则难以防范CSRF攻击。
JWT方式
什么是Token?
在Web应用中,Token是一个代表系统中某个实体(通常是用户会话)的加密字符串,用于在客户端和服务器间安全传递信息。Token可以存储所需的任何数据,但为了减少客户端到服务器的往返次数,它通常包含足够的信息来标识用户或会话,以及签名或其他验证数据,以确保Token的真实性和完整性。
基于Token的会话管理
基于Token的会话管理是一种服务器无状态的认证机制。传统的基于会话的认证会在服务器上存储用户的登录信息,而基于Token的认证则不会在服务器上保存会话信息。当用户使用他们的凭证登录时,服务器会创建一个Token(有时候这个Token会有一个过期时间),然后把它发回给用户,用户将Token存储在客户端,并随后的每个请求一起发送。服务器接收到请求后,会验证Token的签名,确认Token有效,然后提取Token中的用户信息,进行权限验证,而不需要查询数据库或保存会话信息。
基于Token的认证的优势
跨平台和跨域认证:Token可以在不同类型的客户端(如Web应用、移动应用)之间共享和使用。
无状态和可扩展性:服务器不需要保存会话信息,使得应用更易于扩展。
安全性:由于Token是加密的,因此安全性较高,特别是在使用HTTPS时。
JWT方式
JWT(JSON Web Tokens)是一种开放标准(RFC 7519),用于安全地在两个参与方之间传递信息作为JSON对象。由于信息可以被验证和信任,因为它是数字签名的(使用HMAC算法或RSA公钥/私钥对进行签名),JWT广泛用于Web应用中的授权和信息交换。
简单来说就是一种基于JSON格式的Token。知识定义了一种基于Token的会话管理的规则,涵盖Token需要包含的标准内容和Token的生成过程,特别适用于分布式站点的单点登录场景
一个JWT实际上是一个被编码的字符串,由三部分组成,用点(.)分隔:
Header(头部):通常包含两部分,token类型(即"JWT")和所使用的签名算法(如HMAC SHA256或RSA)。
Payload(负载):包含所要传递的声明。声明是关于实体(通常是用户)和其他数据的声明。可以包含多种预定义的声明(如发行人、过期时间等)和自定义声明。
Signature(签名):对前两部分的签名,用于验证消息在传递过程中未被篡改。
JWT是实现基于Token认证的一种非常流行的方式,由于其紧凑和自包含的特性,使其成为Web服务认证和信息交换的一个优秀选择。
点分隔三部分一次代表头部,负载,签名。
头部和负载以JSON形式存在,这就是JWT中的Json,三部分的内容都分别单独经过了Base64编码,以.拼接成一个JWT Token。
payload就是指定里面装了什么东西。
注意JWT默认是不加密的,任何人都可以读到,所以不要把密码信息防止这个部分,这个JSON对象也要使用Base64URL算法转成字符串。最好存帮助你去鉴定你是什么角色,这样的数据。
Signature
Signature是对前两部分的签名,确保JWT在传输过程中没有被篡改。
第一个内容就是signature如何生成:
从下面就可以看出来生成的过程
1.先将header经过Base64编码,payload也是经过Base64编码,然后两个字符串用.进行拼接成一个字符串。
2.然后使用Header中指定的算法对这个字符串进行加密,在加密的过程中还需要使用到一个只有服务器知道的密钥(对于HMAC)或私钥(对于RSA算法)
3.最后做完这些就得到了Signature。
工作过程:
当服务器接收到一个JWT时,会使用统一的方法(相同的Header、Payload、算法和秘钥)对收到的JWT的前两部分(Header和Payload)进行签名,然后将这个新生成的签名与JWT中的Signature进行比对。如果两者相同,说明这个JWT是合法的,且数据没有被篡改;如果不同,则验证失败,数据可能被篡改。
我再举个实际的例子:
假设有这样一个JWT,它由三部分组成,Header、Payload和Signature,用点.连接。
生成JWT的过程:
Header (Base64编码后): eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
解码后: {“alg”:“HS256”,“typ”:“JWT”}
Payload (Base64编码后): eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
解码后: {“sub”:“1234567890”,“name”:“John Doe”,“admin”:true}
Signature: 使用Header里声明的HS256算法和一个只有服务器知道的秘钥secret,对{Base64编码的Header}.{Base64编码的Payload}进行加密得到。
服务器生成了JWT发给了用户。
验证JWT的过程:
当用户在之后的请求中返回这个JWT时,服务器需要验证这个JWT是否有效。
服务器首先从JWT中分离出Header和Payload。
然后,服务器使用存储的相同的秘钥secret和JWT Header中声明的相同算法HS256,对{Base64编码的Header}.{Base64编码的Payload}这部分再次进行加密。
加密后,服务器得到了一个新的Signature。
现在,服务器有了两个Signature:
用户发送过来的JWT里的Signature。
服务器自己刚刚生成的Signature。
如果这两个Signature完全相同,那么就说明用户发送过来的JWT在传输过程中没有被篡改,因为只有使用了相同的秘钥和数据才能生成相同的Signature。服务器就认为这个JWT是有效的,用户的请求是合法的。
举个具体的例子:
假设用户发送过来的JWT的Signature是S1。
服务器使用秘钥secret对用户JWT的Header和Payload部分进行加密,假设得到的新Signature是S2。
如果S1等于S2,说明JWT有效,请求合法。
如果S1不等于S2,说明JWT可能在传输过程中被篡改,服务器将拒绝这个请求。
通过这种方式,JWT的Signature保证了传输数据的完整性和安全性。
JWT优缺点
优点:就是Token的优点(最大的优势就是服务端不需要存储Session)
缺点: 由于 有效期存储在Token中,JWT Token一旦签发,就会在有效期内一直可用,无法在服务端废止,当用户进行登出操作,只能依赖客户端删除掉本地的JWT Token,如果需要禁用用户,单词使用JWT就无法做到。(所以通常TOKEN的过期时间都设置的比较短)
如果想实现禁用用户,那可以使用一个黑名单,用之前检查一下,但是这样背离了我们使用Token的初衷,我们想的就是不要在服务端存储数据。这只是一个思路,不是说服务端不让你存储。
实践
go语言要使用jwt-go来实现我们生成JWT和解析JWT的功能。