作者回复: 你好,谢谢你的反馈问题,按照最初的OAuth2规范,SPA单页应用建议是使用简化(Implicit)模式的,这种模式下,应用只传clientId,不传secret,而且获取的令牌也是放在浏览器端(一般是localstorage)的。因为这种模式安全性比较弱,所以一般只限于安全不严格的有限场景。 OAuth2 6749规范制定时间比较早,现在单页SPA开始流行起来,所以这个规范也一直在修订,有些补充规范提出SPA可使用一种授权码+PKCE模式,但我看过应用端实现比较复杂,且对AuthServer有要求,可参考一篇较新文档(https://auth0.com/blog/oauth2-implicit-grant-and-spa/)。 对于正式的授权码模式,令牌会存在Web服务器上,它和后台API交互是会使用令牌,用户浏览器中没有令牌(因为它不直接和后台API交互),浏览器和Web服务器之间可以有Session,而且这个Session可以和某个令牌关联。 如果你要使用单页SPA,又想比较好的安全性,推荐一种oauth-proxy做法,相对比较简单,这个oauth-proxy作为代理,可以让单页SPA实现授权代模式,而且简单可靠,具体做法参考这里的github站点代码(https://github.com/madumalt/oauth-proxy),这做法其实通过扩展网关也可以实现,它可以做到令牌存proxy端(有状态),也可以用加密cookie方式(无状态),而且不会在SPA应用中暴露clientId/secret。
作者回复: 你好,oauth-proxy主要解决两个问题,一个是将clientid/secret存服务端,保证client验证并且不泄露secret,二是token不流到浏览器端,减少token暴露泄露风险,但是为了实现无状态校验(让token不用存储在服务端,否则需要关联sessionId和查询token很麻烦),所以将token存浏览器cookie,但这又会造成token泄露问题,所以必须加密。 OAuth2主要针对分布式微服务/API场景,特别是开放API,这个时候传统username/password方式就明显不合适了。 传统Web应用基于cookie-session实现登录认证和SSO很普遍也很成熟,未必需要用OAuth2,当然现在有OpenID Connect(在OAuth2基础上构建的轻量身份认证协议)也可以实现登录认证和SSO。 如果你深入下去,不管是Web Session/cookie还是OAuth2/token发现这些机制底层相通,无非是身份权限状态存储和引用标识的问题,达成目标的形式稍有不同而已。你可以根据自己的场景灵活选择,未必需要拘泥,当然安全有个最佳实践,尽量遵循标准保证安全性、扩展性和互操作性,这也是Google/Facebook等大厂一般做法。 另外,SPA也可以用增强的授权码模式,不少授权服务器提供js封装,可以直接应用,例如idenityserver(https://github.com/IdentityModel/oidc-client-js),还有keycloak应该也有js adapter。