IdentityServer4 学习笔记-添加web客户端

294 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情

1.创建客户端新项目

首先我们创建一个空的ASP.NET Core应用程序,Node.js应用程序也可以,只要是web可以访问后端都行。

在~/src目录中创建一个新的“空”ASP.NET Core Web应用程序。您可以使用Visual Studio或从命令行执行此操作:

md JavaScriptClient
cd JavaScriptClient
dotnet new web
2.添加静态文件中间件

1.修改JavaScriptClient项目以在端口5003上运行。

2.该项目运行客户端,我们所需要的只是ASP.NET Core提供构成我们应用程序的静态HTML和JavaScript文件。
Startup.cs中的Configure方法注册静态文件中间件(同时删除其他所有内容):

public void Configure(IApplicationBuilder app)
{
    app.UseDefaultFiles();
    app.UseStaticFiles();
}

中间件将从应用程序的~/wwwroot文件夹中提供静态文件。这是放置HTML和JavaScript文件的地方。如果项目中不存在该文件夹,一定要创建。

3.引用OIDC客户端

1.之前使用现有的库来处理OpenID Connect协议。在这里也需要一个类似的库,除了一个在JavaScript中运行并且设计为在浏览器中运行的库。oidc-client库就是这样一个库,可以通过NPMBower等下载,也可以直接从github下载。

2.使用NPM下载oidc-client

npm i oidc-client
copy node_modules\oidc-client\dist\* wwwroot

3.手动下载oidc-client JavaScript文件,可以到GitHub存储库 并下载JavaScript文件。下载后复制到~/wwwroot中

4. 添加HTML和JavaScript文件

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

5.index.html

这是我们应用程序中的页面,包含登录,注销和调用Web API的按钮的HTML。

<!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>
6.app.js

主要是客户端应用的业务代码

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事件处理程序注册到三个按钮:

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

使用UserManager类从OIDC客户端库来管理OpenID Connect协议。它需要MVC Client中必需的类似配置(尽管具有不同的值)。添加代码以配置和实例化UserManager

var config = {
    authority: "http://localhost:5000",
    client_id: "js",
    redirect_uri: "http://localhost:5003/callback.html",
    response_type: "code",
    scope:"openid profile api1",
    post_logout_redirect_uri : "http://localhost:5003/index.html",
};
var mgr = new Oidc.UserManager(config);

UserManager提供getUserAPI以了解用户是否登录到JavaScript应用程序。使用JavaScript Promise以异步方式返回结果。返回的User对象具有profile包含用户声明的属性。

mgr.getUser().then(function (user) {
    if (user) {
        log("User logged in", user.profile);
    }
    else {
        log("User not logged in");
    }
});

实现的loginapilogout功能。在UserManager提供了signinRedirect登录用户,并且signoutRedirect以注销用户。User在上面的代码中获得的对象还具有access_token可用于向Web API进行身份验证的属性。

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

redirect_uri用户登录IdentityServer后,此HTML文件是指定的页面。将完成与IdentityServer的OpenID Connect协议登录握手。这个代码全部由UserManager之前使用的类提供。登录完成后,可以将用户重定向回主index.html页面。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <script src="oidc-client.js"></script>
    <script>
        new Oidc.UserManager({response_mode:"query"}).signinRedirectCallback().then(function() {
            window.location = "index.html";
        }).catch(function(e) {
            console.error(e);
        });
    </script>
</body>
</html>
8.客户注册加入IdentityServer的JavaScript客户端

需要在IdentityServer中为这个新的客户端定义一个配置。在IdentityServer项目中找到客户端配置(在Config.cs中)。将新客户端添加到应用程序的列表中。

// JavaScript Client
new Client
{
    ClientId = "js",
    ClientName = "JavaScript Client",
    AllowedGrantTypes = GrantTypes.Code,
    RequirePkce = true,
    RequireClientSecret = false,

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

    AllowedScopes =
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        "api1"
    }
}
9. 配置CORS

ConfigureServicesStartup.cs中将CORS服务添加到依赖注入系统:

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:

public void Configure(IApplicationBuilder app)
{
    app.UseCors("default");

    app.UseAuthentication();

    app.UseMvc();
}