SPA 如何在 OAuth2 隐式流中提取访问令牌
Posted
技术标签:
【中文标题】SPA 如何在 OAuth2 隐式流中提取访问令牌【英文标题】:How does a SPA extract access token in OAuth2 implicit flow 【发布时间】:2018-10-21 10:56:06 【问题描述】:我有一个基于 Angular 的 SPA,并希望利用 OAuth2 隐式流 OAuth2 implicit flow
当授权服务器建立后,如果我与它有一个活跃的会话并且我发送把这个 URL 放在浏览器地址栏中
https://server.example.com/authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
我使用 access_token 正确重定向到
HTTP/1.1 302 Found
Location: http://client.example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAAs&state=xyz&token_type=example&expires_in=3600
规范规定client.example.com/cb
应该返回一个能够访问完整重定向 URI 的网页(通常是带有嵌入脚本的 html 文档),包括用户代理保留的片段,并提取访问令牌。我已经实现了一个页面,脚本从window.location.hash
获取 access_token 并且它可以工作。
现在,由于 SPA 已经加载,而且我还需要为令牌续订执行此操作,因此我想使用 ajax 请求来执行此操作。但是,使用 ajax 时,会自动执行重定向,我只得到 HTML 页面,但 access_token 丢失了。我可以在响应的 Location 标头中看到 access_token,但不知道如何访问它。
Auth0 和Okta 似乎支持使用隐式流的静默身份验证,它们是如何做到的?
任何帮助将不胜感激。
【问题讨论】:
【参考方案1】:access_token 只能通过location.hash
访问,而 ajax 请求不会更新它,因此无法通过 ajax 请求来实现。
查看了其他库的做法,发现: https://github.com/damienbod/angular-auth-oidc-client#silent-renew
诀窍是创建一个隐藏的iframe
,并且每当需要令牌时,将src
属性更新为构造的URL。令牌将在 iframe 中可用,只需将其传递给 window.parent
。
要实现这一点,首先将一个事件监听器附加到window
window.addEventListener("message", receiveToken, false);
function receiveToken(event)
// event.data will contain hash value
console.log ('token received ' + event.data) ;
并在需要新令牌时调用此函数
function fetchToken()
document.getElementById('iframe').src='https://server.example.com/authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb'
而http://client.example.com/cb
应该返回类似这样的内容
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
window.parent.postMessage(location.hash, "http://client.example.com");
</script>
</head>
<body></body>
</html>
这里postMessage
的第二个参数是targetOrigin
,它应该匹配托管SPA 的主机名。如果你不想要这个安全限制,可以设置为'*'
【讨论】:
以上是关于SPA 如何在 OAuth2 隐式流中提取访问令牌的主要内容,如果未能解决你的问题,请参考以下文章
在 OAuth 2.0 隐式流中验证 nonce 的位置?
是否可以仅请求用户已在 Azure AD OAuth2 隐式流中同意的范围的子集?