asp.net core系列 58 IS4 基于浏览器的JavaScript客户端应用程序

一. 概述

  本篇探讨使用"基于浏览器的JavaScript客户端应用程序"。与上篇实现功能一样,只不过这篇使用JavaScript作为客户端程序,而非core mvc的后台代码HttpClient实现。 功能一样:用户首先要登录IdentityServer站点,再使用IdentityServer发出的访问令牌调用We??b API,可以注销IdentityServer站点下登录的用户,清除cookie中的令牌信息。所有这些都将来自浏览器中运行的JavaScript。

  此示例还是三个项目:

    IdentityServer令牌服务项目 http://localhost:5000

    API资源项目 http://localhost:5001

    JavaScript客户端项目 http://localhost:5003

  开源Github

二. IdentityServer项目

  1.1 定义客户端配置

    Config.cs中,定义客户端,使用code 授权码模式,即先登录获取code,再获取token。项目其它处代码不变。

       public static IEnumerable<Client> GetClients()
        {
            return new List<Client>
            {
                // JavaScript Client
                new Client
                {
                    ClientId = "js",
                    ClientName = "JavaScript Client",
                    //授权码模式
                    AllowedGrantTypes = GrantTypes.Code,
                    //基于授权代码的令牌是否需要验证密钥,默认为false
                    RequirePkce = true,
                    //令牌端点请求令牌时不需要客户端密钥
                    RequireClientSecret = false,

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

                    //指定跨域请求,让IdentityServer接受这个指定网站的认证请求。
                    AllowedCorsOrigins =     { "http://localhost:5003" },

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

    

三. API项目

  在Web API项目中配置 跨域资源共享CORS。这将允许从http:// localhost:5003 (javascript站点) 到http:// localhost:5001 (API站点) 进行Ajax调用(跨域)。项目其它处代码不变。

       public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvcCore()
                .AddAuthorization()
                .AddJsonFormatters();

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

                    options.Audience = "api1";
                });

            //添加Cors服务
            services.AddCors(options =>
            {
                // this defines a CORS policy called "default"
                options.AddPolicy("default", policy =>
                {
                    policy.WithOrigins("http://localhost:5003")
                        .AllowAnyHeader()
                        .AllowAnyMethod();
                });
            });
        }
        public void Configure(IApplicationBuilder app)
        {
            //添加管道
            app.UseCors("default");
            app.UseAuthentication();
            app.UseMvc();
        }

  

四. JavaScript客户端项目

    在项目中,所有代码都在wwwroot下,没有涉及到服务端代码,可以完全不用core程序来调用。目录如下所示:

    其中添加了两个html 页(index.html, callback.html),一个app.js文件,这些属于自定义文件。oidc-client.js是核心库。

  4.1 index页面

    用于调用登录、注销、和api。引用了oidc-client.js和app.js 

<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>

  

  4.2 app.js

    是应用程序的主要代码,包括:登录、Api请求,注销。配置与服务端代码差不多,如下所示:

/// <reference path="oidc-client.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‘;
    });
}

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

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",
};
//UserManager类
var mgr = new Oidc.UserManager(config);

//用户是否登录到JavaScript应用程序
mgr.getUser().then(function (user) {
    if (user) {
        log("User logged in", user.profile);
    }
    else {
        log("User not logged in");
    }
});

//登录
function login() {
    mgr.signinRedirect();
}

//跨域请求api
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();
}

  4.3 callback.html

    用于完成与IdentityServer的OpenID Connect协议登录握手。对应app.js中config对象下的redirect_uri: "http://localhost:5003/callback.html"。登录完成后,我们可以将用户重定向回主index.html页面。添加此代码以完成登录过程

<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>

五 测试

  (1) 启动IdentityServer程序http://localhost:5000

  (2) 启动API程序http://localhost:5001。这二个程序属于服务端

  (3) 启动javascriptClient程序 http://localhost:5003

  (4) 用户点击login,开始握手授权,重定向到IdentityServer站点的登录页

  (5) 输入用户的用户名和密码,登录成功。跳转到IdentityServer站点consent同意页面

  (6) 点击 yes allow后,跳回到客户端站点http://localhost:5003/index.html,完成了交互式身份认证。

  (7) 调用点击Call API按钮,获取访问令牌,请求受保护的api资源。调用CallAPI 时,是访问的api站点http://localhost:5001/identity。

参考文献

  添加JavaScript客户端

原文地址:https://www.cnblogs.com/MrHSR/p/10735033.html

时间: 2024-10-07 02:16:19

asp.net core系列 58 IS4 基于浏览器的JavaScript客户端应用程序的相关文章

asp.net core 系列 20 EF基于数据模型创建数据库

原文:asp.net core 系列 20 EF基于数据模型创建数据库 一.概述 本章使用 Entity Framework Core 构建执行基本数据访问的 ASP.NET Core MVC 应用程序.使用迁移(migrations)基于数据模型创建数据库,是一种code first模式.可以在Windows 上使用 Visual Studio 2017,或在 Windows.macOS 或 Linux 上使用 .NET Core CLI 来学习.已经安装了NET Core 2.1 SDK,这

asp.net core系列 55 IS4使用Identity密码保护API

原文:asp.net core系列 55 IS4使用Identity密码保护API 一.概述 OAuth 2.0资源(web api)所有者密码授权,允许客户端(Client项目)向令牌服务(IdentityServer项目)发送用户名和密码,并获取代表该用户的访问令牌.在官方文档中讲到:规范通常建议不要使用“资源所有者密码授权”.当用户进行身份验证并请求访问令牌时,使用一个交互式OpenID Connect流程通常要好得多(下篇再了解). 本篇介绍“资源所有者密码授权”是因为这种授权允许我们快

asp.net core系列 56 IS4使用OpenID Connect添加用户认证

一.概述 在前二篇中讲到了客户端授权的二种方式: GrantTypes.ClientCredentials凭据授权和GrantTypes.ResourceOwnerPassword密码授权,都是OAuth2.0协议.本篇使用OpenID Connect添加用户认证,客户端授权是GrantTypes.Implicit隐式流授权,是OCID协议. 本篇示例中只有二个项目:一个IdentityServer的mvc应用程序,一个客户端mvc应用程序(用户client端). 下面介绍身份认证交互流程: (

asp.net core系列 30 EF管理数据库架构--必备知识 迁移

原文:asp.net core系列 30 EF管理数据库架构--必备知识 迁移 一.管理数据库架构概述 EF Core 提供两种主要方法来保持 EF Core 模型和数据库架构同步.一是以 EF Core 模型为基准,二是以数据库为基准. (1)如果希望以 EF Core 模型为准,请使用迁移. 对 EF Core 模型进行更改时,此方法会以增量方式将相应架构更改应用到数据库,以使数据库保持与 EF Core 模型兼容.  (2)如果希望以数据库架构为准,请使用反向工程. 使用此方法,可通过将数

ASP.NET CORE系列【一】搭建ASP.NET CORE项目

原文:ASP.NET CORE系列[一]搭建ASP.NET CORE项目 为什么要使用 ASP.NET Core? NET Core 刚发布的时候根据介绍就有点心里痒痒,微软的尿性都懂的,新东西bug太多,现在2.0也发布很久了,决定研究一下. ASP.NET Core官方文档https://docs.microsoft.com/en-us/aspnet/core/getting-started ASP.NET Core 具有如下优点: 生成 Web UI 和 Web API 的统一场景. 集成

asp.net core系列 36 WebAPI 搭建详细示例

原文:asp.net core系列 36 WebAPI 搭建详细示例 一.概述 HTTP不仅仅用于提供网页.HTTP也是构建公开服务和数据的API强大平台.HTTP简单灵活且无处不在.几乎任何你能想到的平台都有一个HTTP库,因此HTTP服务可以覆盖广泛的客户端,包括浏览器,移动设备和传统的桌面应用程序. ASP.NET Web API 是一个框架,基于.NET Framework 或.NET Core 之上构建 Web API. 从本章开始学习Web API系列时,先从一个示例开始,下面使用A

ASP.NET CORE系列【五】webapi整理以及RESTful风格化

原文:ASP.NET CORE系列[五]webapi整理以及RESTful风格化 介绍 什么是RESTful?  这里不多做赘述,详情请百度! 哈哈,本来还想巴拉巴拉介绍一些webapi, RESTful的, 还是算了,咱们直接上干货!(原因是懒!哈哈) 使用 以前使用过mvc的人对webapi 应该都很熟悉,先看一段熟悉的代码 大伙发现了什么没?跟以往mvc大多数相同,但有些地方不同 ,我们来一起看看有何区别 1.首先SysUsersController上面有一段代码 [Produces("a

asp.net core 系列 15 中间件

原文:asp.net core 系列 15 中间件 一.概述 中间件(也叫中间件组件)是一种装配到应用管道以处理请求和响应的软件. 每个组件:(1)选择是否将请求传递到管道中的下一个组件;(2)可以在管道中的下一个组件之前和之后执行工作. 请求委托用于生成请求管道. 请求委托会处理每个 HTTP 请求.使用以下方法配置请求委托:Run,  Map, Use扩展方法.可以将单个请求委托作为匿名方法(称为内联中间件in-line middleware) 或者可以在可重用类中定义.这些可重用的类和内联

asp.net core系列 28 EF模型配置(字段,构造函数,拥有实体类型)

原文:asp.net core系列 28 EF模型配置(字段,构造函数,拥有实体类型) 一. 支持字段 EF允许读取或写入字段而不是一个属性.在使用实体类时,用面向对象的封装来限制或增强应用程序代码对数据访问的语义时,这可能很有用.无法使用数据注释配置.除了约定,还可以使用Fluent API为属性配置支持字段. 1.1 约定 public class Blog { // _<camel-cased property name> private string _url; public int