企业级前端应用的用户会话管理开发经验的一些分享

笔者之前在社区分享了自己作为一名企业级前端应用开发人员,从事一款名叫 Spartacus 的开源 Storefront 框架过程中积累下来的一些开发经验。

我们这个开源项目的 github 地址:github.com/SAP/spartac...

这款使用 Angular 技术栈开发的 Storefront 应用,基于 100% API 驱动的无头电商架构,Commerce 后台将 Commerce 核心业务通过 OCC(Omni Commerce Connect) API 的方式暴露出来。借助这些 API 和开源的 Spartacus 库,客户可以自行开发具备个性化 UX 的电商网站。

Commerce Cloud 有个名为 Oauth2 的 extension,基于 OAuth 2.0 协议实现了用户认证和令牌颁发/功能,支持 OAuth 2.0 协议定义的包括 Resource Owner Password Flow 在内的全部四种认证流。

Commerce Cloud UI 扮演了 OAuth 2.0 认证框架中的客户端 (Client) 角色,通过消费 Commerce Oauth2 扩展提供的 OAuth 系列 API,实现用户会话管理。

让我们从最初始的用户登录场景说起。

输入用户名和密码:

SAP Commerce Cloud UI 调用 Commerce OAuth2 API,endpoint 为 /authorizationserver/oauth/token, 将用户名,密码,client_id 和 client_secret 去换取访问令牌(Access Token)和刷新令牌(Refresh Token).

这里的 SAP Commerce Cloud UI 作为 OAuth 认证体系里的客户端,其 client_id 和 client_secret 在 Commerce Backoffice 里配置:

服务器端验证通过后,会颁发访问令牌和刷新令牌,如下图 access_token 和 refresh_token 字段所示:

SAP Commerce Cloud UI 在 OAuth 体系中扮演的角色是客户端,通过访问令牌,获得访问 Commerce 后台服务器上的业务数据的许可。而刷新令牌,用于当访问令牌过期时,由客户端凭借其换取新的访问令牌。刷新令牌本身是一个凭证,表明持有其的客户端,曾经通过 OAuth 认证,获得了访问受保护资源的许可,当通过刷新令牌再次请求新的访问令牌时,客户端不用再从头开始走一遍 OAuth 认证的完整流程。

SAP Commerce Cloud 的访问令牌和刷新令牌都有过期时间,有时也称为 TTL(Time-to-Live,存活时间),默认值分别为12小时和30天。

而我们团队的开发人员,在开发 SAP Commerce Cloud UI 用户会话管理功能,进行各种边界条件的测试时,为了方便起见,通常将自己本地搭建的 Commerce 服务器上令牌的过期时间进行了调整。比如下图的例子,二者分别调整为30秒和60秒之后过期:

访问令牌获取之后,在接下来 Commerce Cloud UI 消费后台 OCC API 时,会将其附加在 HTTP 请求的头部字段里:

如果此时访问令牌已经过期,则该请求会收到服务器 401 错误的应答:

以及错误详情 InvalidTokenError:Access token expired: IqQ-8cYzHV1gjQOpnYytHTFPt30

显然这种偏技术的错误消息不应该显示给用户,幸运的是我们还有刷新令牌。此时,SAP Commerce Cloud UI 会将过期的访问令牌,连同刷新令牌一齐发送给 Commerce 后台,申请一个新的访问令牌:

SAP Commerce Cloud UI 初次登录申请令牌时,grant_type 的值为 password;而访问令牌过期,使用刷新令牌重新申请时,grant_type 的值应该填充为 refresh_token.

如果刷新令牌的过期时间也到达了,该怎么办?没有刷新令牌,也就无从获取新的访问令牌。因此,我们会将用户重定向到登录页面,显示一条"Session expired"的提示信息,让其登录之后,重新获取访问令牌和刷新令牌。

我们在淘宝网上购物,如果不小心刷新了浏览器,只要客户端存储的 Cookie 尚未过期,就可仍然保持登录状态。这样,客户刷新之前的会话,比如添加商品到购物车,或者正在进行结帐的某一步,仍然处于有效状态。

SAP Commerce Cloud UI 通过将访问令牌持久化到浏览器的 Local Storage 中来实现上述场景。

每当用户成功登录后,我们将 Commerce 后台服务器颁发的访问令牌进行持久化存储,保存到浏览器 Local Storage 中。

每次 SAP Commerce Cloud UI 初始化时,通过 Angular APP_INITIALIZER 这个注入令牌,我们开发了 AuthStatePersistenceService 服务,将浏览器本地存储中的令牌同步到内存中。

采取这种设计后,即使用户在购物过程中刷新了浏览器,SAP Commerce Cloud UI 重新加载后,从 Local Storage 中取出访问令牌同步到内存中,接下来的用户操作,继续使用该令牌调用 Commerce OCC API,不会因浏览器刷新而中断。

总结

SAP Commerce Cloud UI 有关访问令牌和刷新令牌的使用场景如下:

(1) 用户登录后,SAP Commerce Cloud UI 将服务器颁发的访问令牌存储于内存中,并持久化到浏览器 Local Storage.

对于刷新令牌,出于安全性考虑,我们团队实现时,仅将其维护在应用内存中,并不进行持久化操作。

(2) 当用户操作 UI,触发 API 调用后收到服务器返回的访问令牌过期的错误之后,SAP Commerce Cloud UI 自动利用刷新令牌,申请新的访问令牌;待拿到新的访问令牌之后,使用该令牌重新调用之前因为旧的访问令牌过期而失败的 API;这一系列机制对于用户来说完全透明,用户在界面上的操作不会受到任何影响。

(3) 如果用户操作触发的 API 调用收到的服务器返回为刷新令牌过期,SAP Commerce Cloud UI 会暂存当前用户浏览页面的 URL,并将用户重定向到登录页面;用户重新登录后,获取到新的访问令牌和刷新令牌,再被 SAP Commerce Cloud 重定向到刷新令牌过期时正在操作的页面。

本文简单介绍了 SAP Commerce Cloud UI 用户会话管理的基本实现原理和支持的场景。对其技术实现感兴趣的朋友,可以查阅我们团队发布在 Github 上的文档,感谢阅读。

相关推荐
Domain-zhuo4 分钟前
Git常用命令
前端·git·gitee·github·gitea·gitcode
菜根Sec34 分钟前
XSS跨站脚本攻击漏洞练习
前端·xss
m0_7482571841 分钟前
Spring Boot FileUpLoad and Interceptor(文件上传和拦截器,Web入门知识)
前端·spring boot·后端
桃园码工1 小时前
15_HTML5 表单属性 --[HTML5 API 学习之旅]
前端·html5·表单属性
百万蹄蹄向前冲2 小时前
2024不一样的VUE3期末考查
前端·javascript·程序员
轻口味2 小时前
【每日学点鸿蒙知识】AVCodec、SmartPerf工具、web组件加载、监听键盘的显示隐藏、Asset Store Kit
前端·华为·harmonyos
alikami2 小时前
【若依】用 post 请求传 json 格式的数据下载文件
前端·javascript·json
吃杠碰小鸡3 小时前
lodash常用函数
前端·javascript
emoji1111113 小时前
前端对页面数据进行缓存
开发语言·前端·javascript
泰伦闲鱼3 小时前
nestjs:GET REQUEST 缓存问题
服务器·前端·缓存·node.js·nestjs