Authentication with oidc-client.js and Identityserver4 in a React frontend
最近,我正在尝试将IdentityServer4与React客户端一起设置身份验证。我遵循了IdentityServer文档的
缺点是我将React用作前端,对React的了解不足以实现使用React的教程中使用的相同功能。
但是,我开始阅读并尝试开始使用它。我的IdentityServer项目和API已设置并且似乎正常运行(也已与其他客户端进行了测试)。
我首先将oidc-client.js添加到我的Visual Code项目中。接下来,我创建了一个页面,该页面从一开始就呈现出来(名为Authentication.js),在这里包含了Login,Call API和Logout按钮。该页面(Authentication.js)如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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 ( <button id="login" onClick={() => {login()}}>Login</button> <button id="api" onClick={() => {api()}}>Call API</button> <button id="logout" onClick={() => {logout()}}>Logout</button> [cc] |
<路由精确路径=" / callback" render = {()=> {window.location.href =" callback.html"}} />
{/ * {
);
}
}
code> pre>
在testoidc.js文件(上面已导入)中,我添加了所有使用的oidc函数(示例项目中的app.js)。路由部分应使callback.html可用,我将该文件保留为原样(这可能是错误的)。
testoidc.js文件包含以下功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | 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 + '\ \ '; }); } 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的登录页面(很好)。当我使用有效的凭据登录时,我将重定向到我的React应用程序:http:// localhost:3000 / callback.html#id_token = Token
Identity项目中的此客户端定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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" } } |
尽管似乎从未调用过回调函数,但它仅停留在回调URL上,后面带有很长的标记。
另外,getUser函数在登录后仍显示"用户未登录",并且"调用API"按钮一直在说没有令牌。因此,显然事情无法正常进行。我只是不知道哪一点出了问题。
检查时,我可以看到本地存储区中生成了一个令牌:
同样,当我单击注销按钮时,我会重定向到Identity Host的注销页面,但是当我单击注销时,我不会重定向到我的客户端。
我的问题是:
- 我是否可以与IdentityServer4一起实现oidc-client?
- 我使用的是正确的库还是需要与oidc-client.js不同的库?
- 是否有任何教程将React前端与IdentityServer4和oidc-client(无redux)结合使用,我找不到任何教程。
- 如何/在何处添加callback.html,应将其重写?
有人可以向我指出正确的方向,这里很可能有更多的问题出了问题,但此刻我只是停留在开始的地方。
IdentityServer4只是OIDC的后端实现。因此,您要做的就是使用给定的API在客户端中实现流程。我不知道oidc-client.js文件是什么,但它很可能会执行您自己实现的相同操作。流程本身非常简单:
- 如果用户未登录,则显示一个登录框
- 如果需要同意书(类似于您在某些应用中通过Facebook / Google登录),请显示必要的互动
-
如果用户已通过身份验证和授权,请使用新参数将页面重定向到
redirect_uri 。对于您的情况,您的URL将如下所示:https://example.com/cb#access_token=...&id_token=...&stuff-like-nonce-and-state
实现逻辑的最简单方法是首先在路由器中设置一个路由,该路由解析为将执行逻辑的组件。该组件可以是"不可见的"。它甚至不需要渲染任何东西。您可以这样设置路线:
1 | <Route path="/cb" component={AuthorizeCallback} /> |
然后,在
另外,请记住,如果授权服务器的会话cookie没有过期,则如果令牌已过期或删除,则无需重新登录。如果令牌已过期,这将很有用,但注销时可能会出现问题。这就是为什么注销时,需要立即向授权服务器发送删除/过期令牌的请求,然后再从存储中删除令牌。