IdentityServer4-13 - 添加JavaScript客户端

IdentityServer4 添加JavaScript客户端

这个快速入门将展示如何构建一个JavaScript客户端应用程序。 用户将登录到IdentityServer,使用IdentityServer发出的访问令牌调用Web API,并注销IdentityServer。

创建一个JavaScript客户端新项目

为JavaScript应用程序创建一个新项目。 它可以只是一个空的Web项目,或者一个空的ASP.NET Core应用程序。 这个快速入门将使用一个空的ASP.NET Core应用程序。

创建一个新的Asp.NET Core web应用程序:

选择“空”模版:

修改端口

将端口修改为5003 请参阅 http://blog.chenlis.com/2018/01/10/IdentityServer4-12

添加静态文件中间件

考虑到这个项目主要是为了运行客户端,我们需要ASP.NET Core来提供静态HTML和JavaScript文件,这些文件将组成我们的应用程序。 静态文件中间件被设计来做到这一点。

在Startup.cs中的Configure方法中注册静态文件中间件:

1
2
3
4
5
public void Configure(IApplicationBuilder app)
{
app.UseDefaultFiles();
app.UseStaticFiles();
}

这个中间件现在将从应用程序的〜/ wwwroot文件夹中提供静态文件。 我们将把的HTML和JavaScript文件放入到此文件件中。

引用oidc客户端

在MVC项目中,我们使用了一个库来处理OpenID Connect协议。 在这个项目中,我们需要一个类似的库,使用JavaScript编写可以在浏览器中运行的库。 oidc-client库是一个这样的库。 它可以通过NPM,Bower,以及从github直接下载。

NPM

如果你需要使用NPM下载oidc-client库,你需要遵循下面的步骤:

添加一个NPM的包文件”package.json”

1
2
3
"devDependencies": {
"oidc-client": "1.4.1"
}

保存此文件后,Visual Studio应自动将这些软件包恢复到名为node_modules的文件夹中:

〜/ node_modules / oidc-client / dist文件夹中找到名为oidc-client.js的文件,并将其复制到应用程序的〜/ wwwroot文件夹中。 有更复杂的方法将你的NPM软件包复制到〜/ wwwroot,但是这些技术已经超出了这个快速入门的范围。

添加HTML和JavaScript文件

接下来是将你的HTML和JavaScript文件添加到〜/ wwwroot。 我们将添加两个HTML文件和一个特定于应用程序的JavaScript文件(除了oidc-client.js库)。 在〜/ wwwroot中,添加一个名为index.htmlcallback.html的HTML文件,并添加一个名为app.js的JavaScript文件。

index.html

这将是我们应用程序的主页。 它将只包含用于登录,注销并调用Web API的按钮的HTML。 它还将包含标签以包含我们的两个JavaScript文件。 它还将包含用于向用户显示消息的标签。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<button id="login">Login</button>
<button id="api">Call API</button>
<button id="logout">Logout</button>

<pre id="results"></pre>

<script src="oidc-client.js"></script>
<script src="app.js"></script>
</body>
</html>

app.js

这将包含我们的应用程序的主要代码。 首先要添加一个辅助函数来将消息记录到:

1
2
3
4
5
6
7
8
9
10
11
12
13
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';
});
}

接下来,添加代码注册三个按钮的“click”事件处理程序:

1
2
3
document.getElementById("login").addEventListener("click", login, false);
document.getElementById("api").addEventListener("click", api, false);
document.getElementById("logout").addEventListener("click", logout, false);

接下来,我们可以使用oidc-client库中的 UserManager类来管理OpenID Connect协议。 它需要MVC客户端中所需的类似配置(尽管值不同)。 添加此代码来配置和实例化UserManager

1
2
3
4
5
6
7
8
9
var config = {
authority: "http://localhost:5000",
client_id: "js",
redirect_uri: "http://localhost:5003/callback.html",
response_type: "id_token token",
scope:"openid profile api1",
post_logout_redirect_uri : "http://localhost:5003/index.html",
};
var mgr = new Oidc.UserManager(config);

接下来,UserManager提供一个getUser API来知道用户是否登录到JavaScript应用程序。 它使用JavaScript Promise异步返回结果。 返回的用户对象具有包含用户身份单元的配置文件属性。 添加此代码来检测用户是否登录到JavaScript应用程序:

1
2
3
4
5
6
7
8
mgr.getUser().then(function (user) {
if (user) {
log("User logged in", user.profile);
}
else {
log("User not logged in");
}
});

接下来,我们要实现登录,访问api和注销功能。

UserManager提供signinRedirect来登录用户,signoutRedirect登出用户。 我们在上面的代码中获得的User对象也有一个access_token属性,可以用来通过web API进行认证。 access_token将通过Bearer方案的Authorization头(JWT)传递给Web API。 添加此代码以在我们的应用程序中实现这三个函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function login() {
mgr.signinRedirect();
}

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();
});
}

function logout() {
mgr.signoutRedirect();
}

callback.html

一旦用户登录到IdentityServer,该HTML文件就是指定的redirect_uri页面。 它将完成与IdentityServer的OpenID Connect协议登录握手。 这个代码全部由我们之前使用的UserManager类提供。 登录完成后,我们可以将用户重定向到主index.html页面。 添加此代码以完成登录过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<script src="oidc-client.js"></script>
<script>
new Oidc.UserManager().signinRedirectCallback().then(function () {
window.location = "index.html";
}).catch(function (e) {
console.error(e);
});
</script>
</body>
</html>

为JavaScript客户端添加客户端注册到IdentityServer

现在客户端应用程序已经准备就绪,我们需要在IdentityServer中为这个新的JavaScript客户端定义一个配置条目。 在IdentityServer项目中找到客户端配置(在Config.cs中)。 为我们的新JavaScript应用程序添加一个新的客户端到列表中。 它应该有以下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// JavaScript Client
new Client
{
ClientId = "js",
ClientName = "JavaScript Client",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,

RedirectUris = { "http://localhost:5003/callback.html" },
PostLogoutRedirectUris = { "http://localhost:5003/index.html" },
AllowedCorsOrigins = { "http://localhost:5003" },

AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
}
}

为webapi添加CORS,允许跨域调用api

最后一个必要的配置是在Web API项目中配置CORS。 这将允许Ajax调用从http://localhost:5003调用http://localhost:5001的webapi。

配置CORS

Startup.csConfigureServices中的将将CORS服务添加到依赖注入系统:

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
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore()
.AddAuthorization()
.AddJsonFormatters();

services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;

options.ApiName = "api1";
});

services.AddCors(options =>
{
// this defines a CORS policy called "default"
options.AddPolicy("default", policy =>
{
policy.WithOrigins("http://localhost:5003")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
}

将CORS中间件添加到Configure中的管道:

1
2
3
4
5
6
7
8
public void Configure(IApplicationBuilder app)
{
app.UseCors("default");

app.UseAuthentication();

app.UseMvc();
}

运行JavaScript应用

现在你应该可以运行JavaScript客户端应用程序了:

点击“Login”按钮登录。一旦用户返回到JavaScript应用程序,你应该看到他们的个人资料信息:

然后点击“API”按钮来调用Web API:

最后点击“Logout”注销用户。

现在,您已经有了一个JavaScript客户端应用程序的开始,该应用程序使用IdentityServer来登录,注销和验证对Web API的调用。