背景:
门户网站分为个人用户,个人开发者,机构用户,页面不同的操作需要特定的用户才能操作。如api申请,密钥下载只有机构用户才可操作,重置密码需要登录后才可操作。
管理端分为系统管理员,开放平台管理员,银行管理员,不同的角色具有不同的权限,
权限按资源划分
服务间调用也需要进行保护,如调用发送短信接口,调用发送站内信的接口,不能不加限制地对外暴露。
因此需要以接口为粒度进行统一鉴权,在接口处注明需要的权限,需注明请求来源:门户,管理端,服务间调用。如果是门户或管理端,还可标注需要的角色或资源。可校验多个来源。

技术设计:
对于门户网站和管理端,用户登录成功后生成包含用户信息(userId)的JWT token,前端保存在vuex中。每次操作请求将token放入front- Authorization和manage- Authorization以供服务端校验。其中front和manage代表源自门户和管理端。
服务间调用发送http请求时,在header处添加service- Authorization,值为有效期为30s的JWT token,service代表源自服务间调用。
通过注解标记需要校验的接口,并添加所需要的请求来源和资源名称,如果匹配则放行,否则报无权限请求。
利用拦截器对请求进行切面操作,如果该方法加@AuthRequest注解则寻找header,若包含front- Authorization,manage- Authorization或service- Authorization,则对该token进行JWT校验。其中front和service校验较为简单,直接校验即刻,manage校验token成功后还需从token中获取userId,通过服务间调用判断该用户是否拥有该资源。如果门户和管理端校验成功,从token中取出userId,role放入attribute,供接口使用。
引入该包还为feign调用添加service- Authorization的header

流程图:
image.png

说明:
门户网站,管理端和服务间调用通常通过gateway,但是统一校验不在gateway,而在各自服务,原因如下:

  • 更安全,有的请求可能直接通过服务调用,而非gateway,因此需要在服务的接口层面做校验
  • 配置更方便

权限是一种安全策略,用户只可访问被授权的资源。因此需要采取策略控制用户的行为。
涉及到以下几个方面:

  • 用户认证:如何校验用户的合法性并保存用户的登录状态
  • 权限校验:如何保护服务端的接口,用户是否有资格调用接口,包括:从web端发送来的请求,服务间的调用
  • 权限管理:如何给用户分配资源,RBAC

权限功能在服务从单体转向微服务架构面临如下挑战:

  • 如何保证用户的登录状态。单体中可将登录状态保存至session中,但微服务中应用被分为多个服务,服务应该是无状态的,不能保存用户的登录状态;
  • 微服务拆分后,调用来源不仅仅是客户端,还有来自服务间的调用,因此需要全面考虑多个来源的调用
  • 权限校验功能不能散落在各个服务中,应统一处理
  • 前后端分离,只做数据交互,前端路由/按钮资源化,如何管理资源

微服务应用的权限功能应具有特点:

  • 与业务系统解耦,功能独立,职责单一
  • 保证可用性,当权限服务不可用时,不能改变业务系统的行为
  • 保证性能,避免因鉴权导致响应时间增加
  • 对已有代码侵入性小,改造方便

现有的解决方案:

  • Oauth2:授权框架
  • JWT token:认证协议
  • Security:有些重
  • Shiro:可做权限认证,密码加密等,但不太适用于微服务环境,SecurityManager
  • 分布式session:将username,session id作为key存储至分布式存储中,用户访问微服务时,可以从分布式存储中判定。保证了高可用和可扩展。缺点是存在安全隐患。

经过比较,决定自行研发一套权限校验框架,包括:

  • JWT Token进行用户认证及鉴权
  • RBAC权限分配体系

架构图:
image.png

Token设计
一段字符串,用户登陆成功后服务端生成返回至客户端保存,作为后续已登陆状态的凭证。
优点:

  • 每次请求将token放入header中,可避免CSRF
  • 自身无状态,可在服务间共享,服务端不保存token仍可校验其合法性。(不用在服务端保存k-v)

应具有以下特点:

  • 一个Token就是一些信息的集合,包含如username,phone-number,资源等信息;
  • 可作为用户认证的凭据。因为token是被签名的,服务端可对cookie和HTTP Authrorization Header进行Token信息的检查,如果校验合法,可认为该请求是安全的
  • Token有一定的有效期,保证安全性
  • Token在有效期内有效,无法通过自身失效,除非通过放入redis辅助校验

过期策略:
Token过期后应进行续签,而不是跳转到登陆画面,造成糟糕的用户体验。Token失效时间过长会存在安全性隐患,过短会造成频繁的refresh token。好的体验应该是在用户无感知的情况下进行token刷新。

  • 服务端保存token状态,用户每次操作均刷新token有效期,可做到一段时间没有操作即登出,但这种方案对内存压力较大,每次操作都要访问,失去了token可被验证的便捷性
  • refresh token:用户登陆成功后返回token及refresh token,token过期后通过refresh token续签token,token有效期短而refresh token有效期长,refresh token失效后认为登出。可实现每次登陆保存登录状态一定时间。可以避免对内存的频繁读写

何时refresh token:

  • 前端建立定时任务每隔一定时间通过refresh token获取新token
  • 收到响应后,如果响应为token过期,通过refresh token获取新token,再次发送请求,如果refresh token过期,说明需重新登录

吃水果毫不费力zz
7 声望0 粉丝

啦啦啦