最近我尝试使用IdentityServer4和React客户端设置身份验证。我按照Adding a JavaScript client
教程(部分)了解了IdentityServer文档:https://media.readthedocs.org/pdf/identityserver4/release/identityserver4.pdf也使用了Quickstart7_JavaScriptClient
文件。
缺点是我使用React作为我的前端,而我对React的了解并不足以实现使用React的教程中使用的相同功能。
然而,无论如何,我开始阅读并试图开始使用它。我的IdentityServer项目和API已设置好,并且似乎正常工作(也与其他客户端一起测试)。
我首先将oidc-client.js添加到我的Visual Code项目中。接下来,我创建了一个在开始时呈现的页面(将其命名为Authentication.js),这是包含Login,Call API和Logout按钮的位置。此页面(Authentication.js)如下所示:
import React, { Component } from 'react';
import {login, logout, api, log} from '../../testoidc'
import {Route, Link} from 'react-router';
export default class Authentication extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<div>
<button id="login" onClick={() => {login()}}>Login</button>
<button id="api" onClick={() => {api()}}>Call API</button>
<button id="logout" onClick={() => {logout()}}>Logout</button>
<pre id="results"></pre>
</div>
<div>
<Route exact path="/callback" render={() => {window.location.href="callback.html"}} />
{/* {<Route path='/callback' component={callback}>callback</Route>} */}
</div>
</div>
);
}
}
在testoidc.js文件中(上面导入了)我添加了所有使用的oidc函数(示例项目中的app.js)。路由部分应该使callback.html可用,我已经保留了该文件(这可能是错误的)。
testoidc.js文件包含以下函数:
import Oidc from 'oidc-client'
export function log() {
document.getElementById('results').innerText = '';
Array.prototype.forEach.call(arguments, function (msg) {
if (msg instanceof Error) {
msg = "Error: " + msg.message;
}
else if (typeof msg !== 'string') {
msg = JSON.stringify(msg, null, 2);
}
document.getElementById('results').innerHTML += msg + '\r\n';
});
}
var config = {
authority: "http://localhost:5000",
client_id: "js",
redirect_uri: "http://localhost:3000/callback.html",
response_type: "id_token token",
scope:"openid profile api1",
post_logout_redirect_uri : "http://localhost:3000/index.html",
};
var mgr = new Oidc.UserManager(config);
mgr.getUser().then(function (user) {
if (user) {
log("User logged in", user.profile);
}
else {
log("User not logged in");
}
});
export function login() {
mgr.signinRedirect();
}
export function api() {
mgr.getUser().then(function (user) {
var url = "http://localhost:5001/identity";
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onload = function () {
log(xhr.status, JSON.parse(xhr.responseText));
}
xhr.setRequestHeader("Authorization", "Bearer " + user.access_token);
xhr.send();
});
}
export function logout() {
mgr.signoutRedirect();
}
有很多事情出错了。当我单击登录按钮时,我被重定向到identityServer的登录页面(这很好)。当我使用有效凭据登录时,我将被重定向到我的反应应用程序:http://localhost:3000/callback.html#id_token=Token
Identity项目中的此客户端定义如下:
new Client
{
ClientId = "js",
ClientName = "JavaScript Client",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
// where to redirect to after login
RedirectUris = { "http://localhost:3000/callback.html" },
// where to redirect to after logout
PostLogoutRedirectUris = { "http://localhost:3000/index.html" },
AllowedCorsOrigins = { "http://localhost:3000" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
}
}
虽然看起来回调函数似乎永远不会被调用,但它只会停留在回调网址上,背后有一个很长的令牌..
此外,getUser函数在登录后仍然显示“用户未登录”,并且Call API按钮一直表示没有令牌。显然事情没有正常工作。我只是不知道它出了什么问题。 检查时,我可以看到在本地存储中生成了一个令牌:
当我点击退出按钮时,我会被重定向到身份主机的注销页面,但当我点击注销时,我不会被重定向到我的客户端。
我的问题是:
有人能指出我正确的方向,这里可能会出现更多错误,但目前我只是陷入了甚至开始的地方。
答案 0 :(得分:0)
IdentityServer4只是OIDC的后端实现;因此,您要做的就是使用给定的API在客户端中实现流程。我不知道oidc-client.js文件是什么,但是它很可能会执行您自己实现的相同操作。流程本身非常简单:
client_id
和redirect_uri
(以及状态,现时)将用户重定向到Auth服务器client_id
和redirect_uri
是否匹配。
redirect_uri
。对于您而言,您的网址将如下所示:https://example.com/cb#access_token=...&id_token=...&stuff-like-nonce-and-state
实现逻辑的最简单方法是首先在路由器中设置一条路由,该路由解析为将执行逻辑的组件。该组件可以是“不可见的”。它甚至不需要渲染任何东西。您可以这样设置路线:
<Route path="/cb" component={AuthorizeCallback} />
然后,在AuthorizeCallback
组件中实现OIDC客户端逻辑。在组件中,您只需要解析URL。您可以使用location.hash来访问URL的#access_token=...&id_token=...&stuff-like-nonce-and-state
部分。您可以使用URLSearchParams或qs之类的第三方库。然后,只需将值存储在某个地方(sessionStorage,localStorage,如果可能,还可以使用cookie)。您要做的其他事情只是实现细节。例如,在我的一个应用中,为了记住用户在应用中所处的活动页面,我将值存储在sessionStorage中,然后使用该存储中的值在AuthorizeCallback
中将用户重定向到正确的页面。因此,Auth服务器重定向到解析为{{1}的“ / cb”,并且该组件根据用户所在的位置重定向到所需的位置(如果未设置位置,则重定向到“ /”)。
此外,请记住,如果授权服务器的会话cookie没有过期,则如果令牌已过期或被删除,则无需重新登录。如果令牌已过期,这将很有用,但注销时可能会出现问题。因此,当您注销时,需要立即向授权服务器发送删除/过期令牌的请求,然后再从存储中删除令牌。