array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 ASP.NET Core3.1使用Identity Server4建立Authorization Server - 爱码网
jellydong

前言

网上关于Identity Server4的资料有挺多的,之前是一直看杨旭老师的,最近项目中有使用到,在使用.NET Core3.1的时候有一些不同。所以在此记录一下。

预备知识: https://www.cnblogs.com/cgzl/p/9405796.html

本文内容参考

如杨旭老师所说,官方文档真的很详细,有时间建议大家看下官方文档。

建立Authorization Server

建立ASP.Net Core项目使用空模板。

项目建立之后,运行方式改为使用控制台运行而不是IIS Express,以便查看各种debug信息。

这个已成为习惯,也是学习杨老师的,确实比较方便,当然如果不喜欢可以不设置,只需要端口号配置的时候对应好就可以的。


修改后文件代码为:

{ 
  "profiles": { 
    "IdentityServer4.AuthServer": {
      "commandName": "Project",
      "launchBrowser": true,
      "applicationUrl": "http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

端口号为5000,此时运行程序,会显示出Hello World!,默认的,没有修改。

安装Identity Server4

点击安装就好啦。

配置Identity Server4

API和客户端

API的配置和之前有所不同,之前是ApiResources,现在分为ApiResourcesApiScopes,后续会说到。

using IdentityServer4.Models;
using IdentityServer4.Test;
using System.Collections.Generic;

namespace IdentityServer4.AuthServer.Configuration
{
    public class InMemoryConfiguration
    {
        /// <summary>
        /// Api Scopes
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<ApiScope> ApiScopes()
        {
            return new List<ApiScope>
            {
                new ApiScope("scope1","scope1")
            };
        }
        /// <summary>
        /// ApiResources
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<ApiResource> ApiResources()
        { 
            return new[]
            {
                new ApiResource
                {
                    Name = "api1",
                    DisplayName = "My Api1",
                    Scopes = { "scope1" }
                } 
            };
        }
        /// <summary>
        /// Clients
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<Client> Clients()
        {
            return new[]
            { 
                new Client
                {
                    ClientId = "client",
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials, 
                    ClientSecrets =
                    {
                        new Secret("secret".Sha256())
                    }, 
                    AllowedScopes = { "scope1" }
                }
            };
        }
        /// <summary>
        /// Users
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<TestUser> Users()
        {
            return new[]
            {
                new TestUser
                {
                    SubjectId = "1",
                    Username = "mail@qq.com",
                    Password = "password"
                }
            };
        }
    }
}

ApiScopes: 这个应该怎么翻译我也不清楚,API范围?如果没理解错的话,就是给之前的ApiResources进行了一个分组。授权的时候会验证Scope

ApiResources:比如官网的第一个demo,可能会有疑问,你怎么知道我是api1呢?其实,就没有验证,只要有授权码就可以访问的。如果说,我只要api1的话,那就用到ApiResources了,生产环境中,也必然是需要用到的。

加载资源和客户端

修改Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddIdentityServer()
        .AddDeveloperSigningCredential()
        .AddTestUsers(InMemoryConfiguration.Users().ToList())
        .AddInMemoryClients(InMemoryConfiguration.Clients())
        .AddInMemoryApiScopes(InMemoryConfiguration.ApiScopes())
        .AddInMemoryApiResources(InMemoryConfiguration.ApiResources());
}

当然,也需要app.UseIdentityServer();

首次启动时,Identity Server4将创建一个开发人员签名密钥,该文件名为tempkey.rsa。不必将该文件签入源代码管理中,如果不存在该文件将被重新创建。也就是AddDeveloperSigningCredential()。 这个方法只适合用于Identity Server4在单个机器运行, 如果是生产环境你得使用AddSigningCredential()这个方法.

运行一下,发现并没有什么改变,不过打开:http://localhost:5000/.well-known/openid-configuration,则应该看到所谓的发现文档。发现文档是身份服务器中的标准端点。客户端和API将使用发现文档来下载必要的配置数据。

获取Token

打开Postman,按照配置的输入然后试一下

获取到Token,控制台输出如下:

这里是有用户的信息的,但是我们可以把用户信息去掉,然后GrantType改为client_credentials,我们设置的是 ResourceOwnerPasswordAndClientCredentials 这个GrantType,所以使用用户名密码以及使用ClientCredentials都可以。

不过此时控制台会有区别,没有用户信息了。

美化美化UI

Identity Server 4 提供了一套QuickStart UI

https://github.com/IdentityServer/IdentityServer4.Quickstart.UI

此存储库包含UI所需的控制器,模型,视图和CSS文件。只需下载/克隆并将其复制到Web项目中即可。

打开项目根目录,运行Powershell,然后输入命令:

iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/IdentityServer/IdentityServer4.Quickstart.UI/main/getmain.ps1'))

不过可能你会遇到我前三次那种错误,嗯,访问不了,那就全局或者先下载下来人工粘贴过去吧~

好了以后我们的项目是酱紫的:

由于有wwwroot下很多静态文件, 所以asp.net core 需要启用服务静态文件的功能: 修改Startup的Configure方法

先看修改前的样子吧

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseIdentityServer();

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
            });
        }

修改后

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseIdentityServer();

            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                   name: "default",
                   pattern: "{controller=Home}/{action=Index}/{id?}"
               );
            });
        }

是不是抛异常了?

因为我们现在有UI了,所以不要忘记在ConfigureServices里面注册MVC。

        public void ConfigureServices(IServiceCollection services)
        {
            
            services.AddControllersWithViews();

            services.AddIdentityServer()
              .AddDeveloperSigningCredential()
              .AddTestUsers(InMemoryConfiguration.Users().ToList())
              .AddInMemoryClients(InMemoryConfiguration.Clients())
              .AddInMemoryApiScopes(InMemoryConfiguration.ApiScopes())
              .AddInMemoryApiResources(InMemoryConfiguration.ApiResources());
        }

然后运行一下试试:

登录一下~

好了,现在我们已经可以登录成功了。

登录界面可以自定义的~,OK,今天就到这里

计划

接下来会说一下

  • 建立我们的API项目并使用Token测试接口
  • 建立一个MVC客户端项目访问我们的API
  • 建立一个JS(Vue)客户端访问我们的API项目

End

推广下自己的公众号一个逗逼的程序员,主要记录自己工作中解决问题的思路分享及学习过程中的笔记。绝对不会程序员贩卖程序员的焦虑来割韭菜

相关文章: