restful架构风格设计准则(五)用户认证和session管理

读书笔记,原文链接:http://www.cnblogs.com/loveis715/p/4669091.html,感谢作者!

Authentication

  其实在上一节中,我们已经提出了无状态约束给REST实现带来的麻烦:用户的状态是需要全部保存在客户端的。当用户需要执行某个操作的时候,其需要将所有的执行该请求所需要的信息添加到请求中。该请求将可能被REST服务集群中的任意服务器处理,而不需要担心该服务器中是否存有用户相关的状态。

  但是在现有的各种基于HTTP的Web服务中,我们常常使用会话来管理用户状态,至少是用户的登陆状态。因此,REST系统的无状态约束实际上并不是一个对传统用户登录功能友好的约束:在传统登陆过程中,其本身就是通过用户所提供的用户名和密码等在服务端创建一个用户的登陆状态,而REST的无状态约束为了横向扩展性却不想要这种状态。而这也就是为基于HTTP的REST服务添加身份验证功能的困难之处。

  为了解决该问题,最为经典也最符合REST规范的实现是在每次发送请求的时候都将用户的用户名和密码都发送给服务器。而服务器将根据请求中的用户名和密码调用登陆服务,以从该服务中得到用户所对应的Identity和其所具有的权限。接下来,在REST服务中根据用户的权限来访问资源。

  这里有一个问题就是登陆的性能。随着系统当前的加密算法越来越复杂,登陆已经不再是一个轻量级的操作。因此用户所发送的每次请求都要求一次登陆对于整个系统而言就是一个巨大的瓶颈。

  在当前,解决该问题的方法主要是一个独立的缓存系统,如整个集群唯一的登陆服务器。但是缓存系统本身所存储的仍然是用户的登陆状态。因此该解决方案将仍然轻微地违反了REST的无状态约束。

  还有一个类似的方法是通过添加一个代理来完成的。该代理会完成用户的登陆并获得该用户所拥有的权限。接下来,该代理会将与状态有关的信息从请求中删除,并添加用户的权限信息。在经过了这种处理之后,这些请求就可以转发到其后的各个服务器上了。转发目的地所在的服务器则会假设所有传入的请求都是合法的并直接对这些请求进行处理。

  可以看到,无论是一个独立的登陆服务器还是为整个集群添加一个代理,系统中都将有一个地方保留了用户的登陆状态。这实际上和在集群中对会话集中进行管理并没有什么不同。也就是说,我们所尝试的通过禁止使用会话来达成完全的无状态并不现实。因此在一个基于HTTP的REST服务中,为登陆功能使用集中管理的会话是合理的。

  既然我们放松了对REST系统的无状态约束,那么一个REST系统所可以使用的登陆机制将主要分为以下两种:

  1.   基于HTTPS的Basic Access Authentication

其好处是其易于实现,而且主流的浏览器都提供了对该功能的支持。但是由于登陆窗口都是由浏览器所提供的,因此其与产品外观有很大不同。除此之外,浏览器都没有提供登出的功能,也没有提供找回密码等功能。

  2.   基于Cookie及Session的管理

在使用Cookie来管理用户的注册状态的时候,其实际上就是将服务端所返回的Cookie在每次发送请求的时候添加到请求中。虽然说这个Cookie并非存储了用户应用的状态,但是其实际存储了用户的登陆状态。因此客户端的角度来讲,由服务端管理的Session并不符合REST所倡导的无状态的要求。

  可以说,上面的两种方法各有优劣。可能第二种方法从客户端的角度看来并不是RESTful的,但是其优势则在于很多类库都直接提供了对该功能的支持,从而简化了会话管理服务器的实现。

  在这里顺便提一句,如果项目足够大,将一些SSO产品集成到服务中也是不错的选择。

时间: 2024-08-02 17:45:27

restful架构风格设计准则(五)用户认证和session管理的相关文章

restful架构风格设计准则(四)资源识别的注意事项

一.资源表示使用 单数 vs. 复数 如果一个URL所对应的资源是使用复数表示的,那么该类型的资源可能有多个.对该URL发送Get请求可能返回该资源的一个列表.如果一个URL所对应的资源是使用单数表示的,那么该类型的资源将只有一个,对该URL发送Get请求将只返回该资源的一个实例. 举例来说,一个网站所售卖的商品可能有多种类别,因此需要在URL中使用复数形式:/API/categories.对于一个该网站的用户只有一个个人偏好设置,因此其URL则需要使用单数形式:/API/users/{user

restful架构风格设计准则(六)版本管理

读书笔记,原文链接:http://www.cnblogs.com/loveis715/p/4669091.html,感谢作者! 版本管理 在前面已经提到过,一个REST系统为资源所抽象出的URI实际上是对用户的一种承诺.但反过来说,软件开发人员也很难预知一个资源的各方面特征如何在未来发生变化,从而提供一个永远不变的URI. 在一个REST系统逐渐发展的过程中,新的属性,新的资源将逐渐被添加到该系统中.在这些更改过程中,资源的URI,访问资源的动词,响应中的Status Code将不能发生变化.此

restful架构风格设计准则(三)资源识别和资源设计

restful风格的设计中,首先要识别系统中的资源,然后用HTTP规范表示这些资源. 一.资源识别 1.以资源为中心 vs 以动作为中心 以动作为中心 在传统的软件分析设计中,常常要分析业务要使用的业务逻辑,并为业务逻辑的执行提供一系列接口.如:将商品放入购物车,提交订单等.这一系列接口组合在一起就可以组成完成目标所需要执行的业务逻辑. 在需要调用这些接口的时候,软件开发人员需要向这些接口所在的URL发送一个请求,从而驱使服务执行该动作. 以资源为中心 而在restful风格的软件分析设计中,我

Nodejs之MEAN栈开发(八)---- 用户认证与会话管理详解

用户认证与会话管理基本上是每个网站必备的一个功能.在Asp.net下做的比较多,大体的思路都是先根据用户提供的用户名和密码到数据库找到用户信息,然后校验,校验成功之后记住用户的姓名和相关信息,这个信息经过处理之后会保存在cookie.缓存.Session等地方,然后还有一个过期时间,避免每次都要去捞数据库.在node下基本上也是这个思路,这一节的内容会涉及到user模型的加密方式.如何生成一个Json Web Token(JWT).以及在客户端用Angular创建注册和登录页面,在请求需要认证的

【摘自大型网站技术架构书】应用服务器集群的session管理

由于负载均衡服务器可能会将请求分发到集群任何一台服务器上,所以保证每次请求能够获得正确的session比单机时复杂. 集群环境下,session管理的主要几种手段 1.session复制 session复制是早期的企业级的使用比较多的一种服务器集群session管理机制.应用服务器开启web容器的session复制功能,在集群中的几台服务器之间同步session对象,使得每台服务器上都保存所有的session信息,这样任何一台宕机都不会导致session的数据丢失,服务器使用session时,直

mongodb之用户/认证/角色/权限管理

前言 用户权限管理很重要,只给需要的权限,防止应用系统漏洞导致脱库 认证和授权 Authentication 认证识别,解决我是谁 Authorization 操作授权,我能做什么 认证机制 MONGODB-CR 官方自定义实现认证机制,通过用户名和密码,通过challenge-response方式,来识别和验证授权.SCRAM-SHA-1认证机制有更好的安全性,新版本默认使用SCRAM-SHA-1.不建议使用MONGODB-CR模式. SCRAM-SHA-1 3.0版本新加功能,Mongodb

搭建docker私有仓库(用户认证、web管理)

ubuntu:16.04 docker:18.06.0-ce docker仓库服务器:192.168.83.102 --------------------------------------分割线-------------------------------------- 1.生成私钥和证书 mkdir conf openssl req -new -newkey rsa:4096 -days 365 -subj "/CN=localhost" -nodes -x509 -keyout

用户认证:基于jwt和session的区别和优缺点

背景知识: Authentication和Authorization的区别: Authentication:用户认证,指的是验证用户的身份,例如你希望以小A的身份登录,那么应用程序需要通过用户名和密码确认你真的是小A. Authorization:授权,指的是确认你的身份之后提供给你权限,例如用户小A可以修改数据,而用户小B只能阅读数据. 由于http协议是无状态的,每一次请求都无状态.当一个用户通过用户名和密码登录了之后,他的下一个请求不会携带任何状态,应用程序无法知道他的身份,那就必须重新认

Django之用户认证功能

前言 做web应用对登录做用户身份认证,然后设置session是比不可少的,因为我们就需要把有权限访问本站视图的用户,单独建一张表记录到数据库里: Django作为一个大而全的框架,已经为我们做好了这些准备: from django.shortcuts import render,HttpResponse,redirect def login(request): if request.method=='GET': return render(request,'login.html') user=