你们好,我是 Guide哥!端午已过,又要开始工做学习啦!html
我发现有不少小伙伴对认证受权方面的知识不是特别了解,搞不清 Session 认证、JWT 以及 Cookie 这些概念。前端
因此,根据我根据平常对这部分学习已经在项目中的实际运用总结了这 13 个相关的问题而且附上了详细的回答。但愿可以对你们有帮助!java
这是一个绝大多数人都会混淆的问题。首先先从读音上来认识这两个名词,不少人都会把它俩的读音搞混,因此我建议你先先去查一查这两个单词到底该怎么读,他们的具体含义是什么。git
说简单点就是:github
稍微正式点(啰嗦点)的说法就是 :面试
认证 :redis
受权:算法
这两个通常在咱们的系统中被结合在一块儿使用,目的就是为了保护咱们系统的安全性。spring
系统权限控制最常采用的访问控制模型就是 RBAC 模型 。数据库
什么是 RBAC 呢?
RBAC 即基于角色的权限访问控制(Role-Based Access Control)。这是一种经过角色关联权限,角色同时又关联用户的受权的方式。
简单地说:一个用户能够拥有若干角色,每个角色有能够被分配若干权限这样,就构形成“用户-角色-权限” 的受权模型。在这种模型中,用户与角色、角色与权限之间构成了多对多的关系,以下图
在 RBAC 中,权限与角色相关联,用户经过成为适当角色的成员而获得这些角色的权限。这就极大地简化了权限的管理。
一般 RBAC 下的权限设计相关的表有5 张,其中有 2 张用于创建表之间的联系:
经过这个权限模型,咱们能够建立不一样的角色并为不一样的角色分配不一样的权限范围(菜单)。
一般来讲,若是系统对于权限控制要求比较严格的话,通常都会选择使用 RBAC 模型来作权限控制。
Cookie
和 Session
都是用来跟踪浏览器用户身份的会话方式,可是二者的应用场景不太同样。
维基百科是这样定义 Cookie
的:
Cookies
是某些网站为了辨别用户身份而储存在用户本地终端上的数据(一般通过加密)。
简单来讲: Cookie
存放在客户端,通常用来保存用户信息。
下面是 Cookie
的一些应用案例:
Cookie
中保存已经登陆过的用户信息,下次访问网站的时候页面能够自动帮你登陆的一些基本信息给填了。除此以外,Cookie
还能保存用户首选项,主题和其余设置信息。Cookie
保存 Session
或者 Token
,向后端发送请求的时候带上 Cookie
,这样后端就能取到 Session
或者 Token
了。这样就能记录用户当前的状态了,由于 HTTP 协议是无状态的。Cookie
还能够用来记录和分析用户行为。举个简单的例子你在网上购物的时候,由于 HTTP 协议是没有状态的,若是服务器想要获取你在某个页面的停留状态或者看了哪些商品,一种经常使用的实现方式就是将这些信息存放在 Cookie
我这里以 Spring Boot 项目为例。
1)设置 Cookie
返回给客户端
@GetMapping("/change-username")
public String setCookie(HttpServletResponse response) {
// 建立一个 cookie
Cookie cookie = new Cookie("username", "Jovan");
//设置 cookie过时时间
cookie.setMaxAge(7 * 24 * 60 * 60); // expires in 7 days
//添加到 response 中
response.addCookie(cookie);
return "Username is changed!";
}
复制代码
2) 使用 Spring 框架提供的 @CookieValue
注解获取特定的 cookie 的值
@GetMapping("/")
public String readCookie(@CookieValue(value = "username", defaultValue = "Atta") String username) {
return "Hey! My username is " + username;
}
复制代码
3) 读取全部的 Cookie
值
@GetMapping("/all-cookies")
public String readAllCookies(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
return Arrays.stream(cookies)
.map(c -> c.getName() + "=" + c.getValue()).collect(Collectors.joining(", "));
}
return "No cookies";
}
复制代码
更多关于如何在 Spring Boot 中使用 Cookie
的内容能够查看这篇文章:How to use cookies in Spring Boot 。
Session
的主要做用就是经过服务端记录用户的状态。 典型的场景是购物车,当你要添加商品到购物车的时候,系统不知道是哪一个用户操做的,由于 HTTP 协议是无状态的。服务端给特定的用户建立特定的 Session
以后就能够标识这个用户而且跟踪这个用户了。
Cookie
数据保存在客户端(浏览器端),Session
数据保存在服务器端。相对来讲 Session
安全性更高。为了保证 Cookie
中信息的安全性,最好能将 Cookie
信息加密而后使用到的时候再去服务器端解密。
那么,如何使用 Session
进行身份验证?
不少时候咱们都是经过 SessionID
来实现特定的用户,SessionID
通常会选择存放在 Redis 中。举个例子:
SessionID
的 Cookie
SessionID
带上,这样后端就知道你的身份状态了。关于这种认证方式更详细的过程以下:
Session
,并将 Session
信息存储起来。SessionID
,写入用户的 Cookie
。Cookie
将与每一个后续请求一块儿被发送出去。Cookie
上的 SessionID
与存储在内存中或者数据库中的 Session
信息进行比较,以验证用户的身份,返回给用户客户端响应信息的时候会附带用户当前的状态。使用 Session
的时候须要注意下面几个点:
Session
的关键业务必定要确保客户端开启了 Cookie
。Session
的过时时间。另外,Spring Session 提供了一种跨多个应用程序或实例管理用户会话信息的机制。若是想详细了解能够查看下面几篇很不错的文章:
Session-Cookie 方案在单体环境是一个很是好的身份认证方案。可是,当服务器水平拓展成多节点时,Session-Cookie 方案就要面临挑战了。
举个例子:假如咱们部署了两份相同的服务 A,B,用户第一次登录的时候 ,Nginx 经过负载均衡机制将用户请求转发到 A 服务器,此时用户的 Session 信息保存在 A 服务器。结果,用户第二次访问的时候 Nginx 将请求路由到 B 服务器,因为 B 服务器没有保存 用户的 Session 信息,致使用户须要从新进行登录。
咱们应该如何避免上面这种状况的出现呢?
有几个方案可供你们参考:
这是一道经典的面试题!
通常是经过 Cookie
来保存 SessionID
,假如你使用了 Cookie
保存 SessionID
的方案的话, 若是客户端禁用了 Cookie
,那么 Session
就没法正常工做。
可是,并非没有 Cookie
以后就不能用 Session
了,好比你能够将 SessionID
放在请求的 url
里面https://javaguide.cn/?Session_id=xxx
。这种方案的话可行,可是安全性和用户体验感下降。固然,为了你也能够对 SessionID
进行一次加密以后再传入后端。
CSRF (Cross Site Request Forgery)通常被翻译为 跨站请求伪造 。那么什么是 跨站请求伪造 呢?说简单用你的身份去发送一些对你不友好的请求。举个简单的例子:
小壮登陆了某网上银行,他来到了网上银行的帖子区,看到一个帖子下面有一个连接写着“科学理财,年盈利率过万”,小壮好奇的点开了这个连接,结果发现本身的帐户少了 10000 元。这是这么回事呢?原来黑客在连接中藏了一个请求,这个请求直接利用小壮的身份给银行发送了一个转帐请求,也就是经过你的 Cookie 向银行发出请求。
<a src=http://www.mybank.com/Transfer?bankId=11&money=10000>科学理财,年盈利率过万</>
复制代码
上面也提到过,进行 Session
认证的时候,咱们通常使用 Cookie
来存储 SessionId
,当咱们登录后后端生成一个 SessionId
放在 Cookie 中返回给客户端,服务端经过 Redis 或者其余存储工具记录保存着这个 SessionId
,客户端登陆之后每次请求都会带上这个 SessionId
,服务端经过这个 SessionId
来标示你这我的。若是别人经过 Cookie
拿到了 SessionId
后就能够代替你的身份访问系统了。
Session
认证中 Cookie
中的 SessionId
是由浏览器发送到服务端的,借助这个特性,攻击者就能够经过让用户误点攻击连接,达到攻击效果。
可是,咱们使用 Token
的话就不会存在这个问题,在咱们登陆成功得到 Token
以后,通常会选择存放在 localStorage
(浏览器本地存储)中。而后咱们在前端经过某些方式会给每一个发到后端的请求加上这个 Token
,这样就不会出现 CSRF 漏洞的问题。由于,即便有个你点击了非法连接发送了请求到服务端,这个非法请求是不会携带 Token
的,因此这个请求将是非法的。
须要注意的是不管是 Cookie
仍是 Token
都没法避免 跨站脚本攻击(Cross Site Scripting)XSS 。
跨站脚本攻击(Cross Site Scripting)缩写为 CSS 但这会与层叠样式表(Cascading Style Sheets,CSS)的缩写混淆。所以,有人将跨站脚本攻击缩写为 XSS。
XSS 中攻击者会用各类方式将恶意代码注入到其余用户的页面中。就能够经过脚本盗用信息好比 Cookie
。
推荐阅读:如何防止 CSRF 攻击?—美团技术团队
咱们在前面的问题中探讨了使用 Session
来鉴别用户的身份,而且给出了几个 Spring Session 的案例分享。 咱们知道 Session
信息须要保存一份在服务器端。这种方式会带来一些麻烦,好比须要咱们保证保存 Session
信息服务器的可用性、不适合移动端(依赖 Cookie
)等等。
有没有一种不须要本身存放 Session
信息就能实现身份验证的方式呢?使用 Token
便可!JWT (JSON Web Token) 就是这种方式的实现,经过这种方式服务器端就不须要保存 Session
数据了,只用在客户端保存服务端返回给客户的 Token
就能够了,扩展性获得提高。
JWT 本质上就一段签名的 JSON 格式的数据。因为它是带有签名的,所以接收者即可以验证它的真实性。
下面是 RFC 7519 对 JWT 作的较为正式的定义。
JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted. ——JSON Web Token (JWT)
JWT 由 3 部分构成:
Token
的类型。Payload
、Header
和一个密钥(secret
)使用 Header
里面指定的签名算法(默认是 HMAC SHA256)生成。在基于 Token 进行身份验证的的应用程序中,服务器经过Payload
、Header
和一个密钥(secret
)建立令牌(Token
)并将 Token
发送给客户端,客户端将 Token
保存在 Cookie 或者 localStorage 里面,之后客户端发出的全部请求都会携带这个令牌。你能够把它放在 Cookie 里面自动发送,可是这样不能跨域,因此更好的作法是放在 HTTP Header 的 Authorization 字段中:Authorization: Bearer Token
。
Header
中带上 JWT。SSO(Single Sign On)即单点登陆说的是用户登录多个子系统的其中一个就有权访问与其相关的其余系统。举个例子咱们在登录了京东金融以后,咱们同时也成功登录京东的京东超市、京东国际、京东生鲜等子系统。
OAuth 是一个行业的标准受权协议,主要用来受权第三方应用获取有限的权限。而 OAuth 2.0 是对 OAuth 1.0 的彻底从新设计,OAuth 2.0 更快,更容易实现,OAuth 1.0 已经被废弃。详情请见:rfc6749。
实际上它就是一种受权机制,它的最终目的是为第三方应用颁发一个有时效性的令牌 Token,使得第三方应用可以经过该令牌获取相关的资源。
OAuth 2.0 比较经常使用的场景就是第三方登陆,当你的网站接入了第三方登陆的时候通常就是使用的 OAuth 2.0 协议。
另外,如今 OAuth 2.0 也常见于支付场景(微信支付、支付宝支付)和开发平台(微信开放平台、阿里开放平台等等)。
微信支付帐户相关参数:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yqIC91bs-1623925796543)(./images/basis-of-authority-certification/微信支付-fnglfdlgdfj.png)]
下图是 Slack OAuth 2.0 第三方登陆的示意图:
推荐阅读:
花了半个月写的最新版 Java学习路线已近更新!多是你看过最用心、最全面的 Java 后端学习路线。
我是 Guide哥,拥抱开源,喜欢烹饪。开源项目 JavaGuide 做者,Github:Snailclimb - Overview 。将来几年,但愿持续完善 JavaGuide,争取可以帮助更多学习 Java 的小伙伴!共勉!凎!点击查看个人2020年工做汇报!
原创不易,欢迎点赞分享,欢迎关注 @JavaGuide,我会持续分享原创干货~
本回答为我本人原创,如需转载,还请注明出处啊!