今日主题:基于spring boot Spring cloud 的微服务认证机制

今日内容

主要是根据公司的公采云产品的认证机制去简单分享一下微服务中的认证流程,从最开始不了解微服务认证机制的时候踩了很多坑,摸爬滚打,最后形成了一套完整的认证机制。

1.简单叙述一下认证机制的发展过程,为什要使用jwt代替session

2.为什么要使用前后端分离(转载一篇文章)

3.微服务的登录认证和请求认证

4.用户退出、用户类型切换机制等

进入今日主题,微服务认证机制;今天主要是理论部分,因为是涉及到公司项目的实现,实际的代码实现还是需要大家自行理解实现;

一、web开发中常见的认证机制

先说说我参与过的项目的认证机制的改变

从最开始的Cookie-Session的认证方式,再到后来的Oauth-Token的认证方式,再到最后的JWT的认证方式。

1.HTTP基本认证(HTTP Basic Auth)

这种认证直接顺应HTTP协议的无状态性,每次执行业务的时候,都暴力地附带username与password参数,并将其发送给服务器进行验证。尽管可以在服务端可以使用Aop技术对于所有请求进行统一拦截,但是如果每次验证都要查询数据库的话,会使得程序开销增大。

2.认证框架使用Cookie-Session Auth

Cookie-Session是我们初期工作中最常见的一种认证机制,比如使用过滤器的方式做权限认证、使用成熟的安全权限框架shiro或spring security等

其实核心原理就是为一次请求认证在服务端创建一个Session对象,同时在客户端的浏览器端创建了一个Cookie对象;在每次请求的时候,携带Cookie,将Cookie中的内容与服务端的Session对象的内容进行匹配来实现状态的管理;但是这种方式随着用户的逐渐增加,会出现很多性能上的问题

因为每个用户在访问系统的时候,都会将session存储在服务端的内存中,随着用户量增大,会导致服务端的开销越来越大,影响系统的性能;

因为用户的认证信息是存储在每个服务端的内存中,所以用户的下一次请求还需要路由到这台机器上,这样才能拿到授权,这样在分布式应用的环境中极大的限制了系统的扩展能力

基于cookie来进行用户识别, cookie如果被恶意获取,用户就会很容易受到CSRF攻击

移动应用中没有Cookie和Session,导致应用无法在移动端使用

针对以上这些情况,也引入了各种机制,比如在使用shiro 的时候,将session中的信息从内存中转移到redis中,这样其他服务也可以获取到该用户的session信息;再比如说使用spring mvc的拦截器来通过判断Referer已达到拦截其他网站的请求,但是Refer是浏览器设置的,在浏览器兼容性大不相同的时代里,如果某种浏览器允许用户修改这种值,那么这种方式也是无法杜绝CSRF攻击的

3.基于oauth-token的认证流程

基于token 的认证方式是无状态的认证方式,无需再服务端保留任何的用户的认证信息,这就意味着token的认证机制不需要知道他在那台机器上进行了登录,这样为服务的横向扩展提供了很大的便利,下图为最常用的授权码模式的流程图:

因为后续要介绍的jwt的认证方式其实就是该认证方式的改良方式,所以该节会更加具体的介绍

微服务的认证授权(如何使用微服务认证机制)(1)

认证流程如下:

1.用户访问客户端Client,客户端判断用户是否有access_token,如果有,则携带access_token正常访问,否则,需要告知浏览器(User-Agent)重定向到授权服务器(Authorizaton Server),授权服务器判断当前环境授权服务是否已登录,若未登录则重定向到浏览器授权页面(User-Agent)

2.用户访问到授权页面,选择是否给予客户端(Client)进行授权,授权服务器(Authorization Server)输入用户名、密码登录进行授权,有的时候比如微信登录,已经是登录状态,则无需输入用户名密码)

3.如果用户拒绝授权,则相应的返回到客户端(Client)的未授权页面;若用户进行授权(或正常输入授权服务器的用户名和密码),授权服务器(Authorization Server)将告知浏览器(User-Agent)重定向到客户端(Client)并带上相应的授权码(Authorization Code)

4.客户端(Client)接收到授权码(Authorization Code)附上重定向地址(Redirect URL)的同时,向授权服务器(Authorization Server )申请认证令牌(access_token)和刷新令牌(refresh_token)

5.授权服务器(Authorization Server )校验授权码(Authorzation Code)和重定向地址(Redirect URL),向客户端颁发认证令牌(access_token)和刷新令牌(refresh_token)

response_type:授权类型,必选项,此处的值固定为"code"

client_id:客户端的ID,必选项

client_secret:客户端的密码,可选

redirect_uri:重定向URI,可选项

scope:申请的权限范围,默认一般为read write

state:客户端的当前状态,可以指定任意值,在我们的微服务中主要是通过这个参数去传递了很多自定义的信息,此处需要进行留意

code:授权码,客户端只能使用一次,重复使用会报错,该码与客户端 ID 和 重定向 URI 是一一对应关系

state:如果客户端请求中包含这个参数,授权服务器的回应也必须一模一样包含这个参数

grant_type:授权模式,必选,此处固定值为“authorization_code”

code:上一步获得的授权吗,必选

redirect_uri:重定向URI,必选,与步骤 1中保持一致

client_id:客户端ID,必选

access_token:认证令牌

token_type:令牌类型

expires_in:过期时间,单位为秒

refresh_token:更新令牌,用来获取下一次的访问令牌

scope:权限范围,和步骤1中的一致一般为read write

之后在访问资源服务器的时候,每次都要直接携带access_token进行访问,具体的使用方式请继续查看第四种认证方式

4.基于token认证方式的JWT认证(JSON Web Token)

1) 什么是jwt

JWT(JSON WEB TOKEN):JSON网络令牌,JWT是一个轻便的安全跨平台传输格式,定义了一个紧凑的自包含的方式在不同实体之间安全传输信息(JSON格式)。它是在Web环境下两个实体之间传输数据的一项标准。实际上传输的就是一个字符串。广义上讲JWT是一个标准的名称;狭义上JWT指的就是用来传递的那个token字符串

2)jwt 的数据结构

jwt实际上长这样,真实的jwt是没有换行的,为方便大家查看,换行展示

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.

eyJhdWQiOlsidW5pdHktcmVzb3VyY2UiXSwidXNlclJlZ2lvbkNvZGVOb3ciOiIiLCJ1c2VyQWNjb3VudCI6ImFkbWluaXN0cmF0b3IiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwic3lzdGVtVHlwZSI6IjEiLCJ1c2VyVHlwZU5vdyI6IjAiLCJ1c2VyTmFtZSI6Iui2hee6p-euoeeQhuWRmCIsImV4cCI6MTU2MzgxOTkxMCwidXNlcklkIjoiMTAwMDAwMDAwMDAwMDAxIiwianRpIjoiMzlmNGJjNDgtNmEyNC00OTQyLTk1OWYtYWQ0OTBiZGNjOWU2IiwiY2xpZW50X2lkIjoiZ3AtZ2F0ZXdheS1jZW50ZXIifQ.

pfTLAyJRrDC5ZbloU5PMBm5O3R9xuyj3EC_NdK_2TPoud-wfNhPMoSdvJpYTcJTOeLkLEnMx_dopJFKB5TF8jnLRLRsRt3g_b46act3NGdMi9-maKL4KcQjGCapKEUxuhgvN9uxv6z6NNac3Xym1_lolhA4W3AzVG7DzCu8TCaLv_l54ie-PZ3vRQggm5308BiYR4-1It2hhxS-mkv4OfoJwWde-vTtSVXqC3QWtFkRl66UsAnCaWdvK3QZ2wAJQZMUjhBhGWlHkcpZCHByY3HabiCoIV6-6stSaCz9ZD39XsnVnTZwUGX0GfAibHErChPe_bksz7hCf9UaYUuRCqw

它是一个很长的字符串,使用点(.)将三部分的Base65编码进行组合,jwt的三个部分主要为:

header(头部)、Payload(负载)、Signature(签名)

主要内容就是base64UrlEncode(Header).base64UrlEncode(Playload).HMACSHA256(base64UrlEncode(header) "." base64UrlEncode(payload),secret)

微服务的认证授权(如何使用微服务认证机制)(2)

alg属性表示签名的算法(algorithm)默认是 HMAC SHA256(写成 HS256)我们项目中使用过的是RS256,同构使用公私密钥对进行加解密;type属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT;然后将这json字符串使用Base64URL算法转成字符串

微服务的认证授权(如何使用微服务认证机制)(3)

playload中主要放置个人的信息,注意啊这部分内容不是加密的,任何人都可以进行解密,所以请不要放置敏感信息;将这json字符串使用Base64URL算法转成字符串

首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

HMACSHA256(base64UrlEncode(header) "." base64UrlEncode(payload),secret)

在我们的项目中主要是使用RS256,通过密钥对来对于数据进行加密,防止因为加密密钥丢失,而导致所有的客户端都能进行验证解密

3)base64URL

前面提到,Header 和 Payload 串型化的算法是 Base64URL。这个算法跟 Base64 算法基本类似,但有一些小的不同。

JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符 、/和=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、 替换成-,/替换成_ 。这就是 Base64URL 算法。

4)jwt的使用

客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。

此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息Authorization字段里面。而且为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。

5)总结

这种认证方式现在已经被很多大型的网站采用,比如FaceBook,GitHub等,但是存储在客户端的token会带来以下一些问题

  1. 存在泄露的风险。如果别人拿到你的 Token,在 Token过期之前,都可以以你的身份在别的地方登录 ,能够获取该jwt的所有权限,对于一些比较重要的权限,使用时应该再次对用户进行认证
  2. 如果存在 Web Storage(指sessionStorage和localStorage)。由于Web Storage 可以被同源下的JavaScript直接获取到,这也就意味着网站下所有的JavaScript代码都可以获取到web Storage,这就给了XSS机会
  3. 如果存在Cookie中。虽然存在Cookie可以使用HttpOnly来防止XSS,但是使用 Cookie 却又引发了CSRF
  4. JWT 不加密的情况下,不能将秘密数据写入 JWT
  5. JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。

二、为什么要使用前后端分离

那么一般在什么情况下会使用jwt这种的认证方式呢,主要是在前后端分离的时候使用这种认证方式,那为什么要使用前后端分离呢?

请查看另一篇转载的文章,为什么要使用前后端分离

今天的主要对于现有的所有认证机制进行一个详细的讲解,以便能让所有不太了解认证机制的同学能够对于认证机制进行简单的学习,下回的分享主要是根据今天的分享内容,对于现有的公采云系统的认证机制进行详细的介绍,以及项目中对于今天所叙述的几个问题的具体的解决方式。

想获取实时的学习资料吗?打开微信,搜索公众号程序员地铁时光,获取最新技术知识

微服务的认证授权(如何使用微服务认证机制)(4)

,