• IdentityServer4


    Client Credential Workflow(工作流)    

        这是一个比较基础的解决方案用IdentityServer保护Resource APIs,在这个工程中定义API和一个访问API的client客户端。Client客户端从IdentityServer获取access token用clientID和clientSecret获取API资源。

       1、创建配置IdentityServer project

         1)、定义Api Scope, api scope是IdentityServer想要保护的资源,demo采用"Code as configuration"的方式,也可以采用其他的方式,比如DB,Redis或者appsettings.json 等.

         Code below: 

    public static IEnumerable<ApiScope> ApiScopes =>
                new List<ApiScope>
                {
                    new ApiScope("api1","My API")
                };

        2)、定义Client, client是将来访问API的客户端

        当前解决方案,client没有交互的user,所以会和IdentityServer通过所谓的client secret认证。

        Code bellow:

    public static IEnumerable<Client> Clients =>
                new List<Client>
                {
                    new Client
                    {
                        AllowedGrantTypes= { OidcConstants.GrantTypes.ClientCredentials },
                        ClientId="client",
                        ClientSecrets =
                        {
                            new Secret("secret".ToSha256())
                        },
                        AllowedScopes  ={"api1"}
                    }
                };

    你可以认为ClientId和ClientSecret 作为你application的登录名和密码,Client将你的application标记到Identity Server以至于知道是哪个application连接的IdentityServer。

    3)、Configuring IdentityServer(配置Identity Server)

    将IdentityServer中间件添加到Services容易中。

    public void ConfigureServices(IServiceCollection services)
    {
         var builder = services.AddIdentityServer()
            .AddInMemoryApiScopes(Config.ApiScopes)
            .AddInMemoryClients(Config.Clients);
          builder.AddDeveloperSigningCredential();
    }

    配置在请求管道中使用IdentityServer中间件

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

    OK,IdentityServer已经配置好了,启动IdentityServer , 在浏览器中访问discovery endpoint,将会显示如下内容:

    Notes:可以在launchsettings.json中修改application的启动方式,当前Demo的配置如下:

    {
      "IdentityServer": {
        "commandName": "Project",
        "launchBrowser": true,
        "applicationUrl": "https://localhost:5001;http://localhost:5000",
        "environmentVariables": {
          "ASPNETCORE_ENVIRONMENT": "Development"
        }
      }
    }

    Discovery Endpoint:

    https://localhost:5001/.well-known/openid-configuration

    Discovery Document Result:

     Notes: 在IdentityServer第一次启动的时候会创建一个developer signing key:tempkey.jwk。

    2、添加一个API application (Asp.NET Core API template)

        配置API为受保护资源,将authentication services添加到DI(dependency injection),authentication middleware 添加到 request pipeline中,作用是:

    • 验证token是颁发自受信任的issuer
    • 验证token是有效的调用API。
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
    
            services.AddAuthentication("Bearer")
                .AddJwtBearer("Bearer", options =>
                {
                    options.Authority = "https://localhost:5001";
    
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateAudience = false
                    };
                });
        }
    
        public void Configure(IApplicationBuilder app)
        {
            app.UseRouting();
    
            app.UseAuthentication();
            app.UseAuthorization();
    
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

    添加一个IdentityServer.Controler, 添加attribute  [Authorize], 意思是只有验证才能访问当前controller,匿名不能访问:(这里的User代表是client application)

        [Route("api/[controller]")]
        [ApiController]
        [Authorize]
        public class IdentityServerController : ControllerBase
        {
            [HttpGet]
            public IActionResult Get()
            {
                return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
            }
        }

    浏览器直接访问,测试结果如下:401 UnAuthorization

    3、添加一个Client用于测试:

        新建一个Console应用程序,向IdentityServer发请求获取token,然后携带这个token发请求获取Resource API资源。

       IdentityServer中的Token Endpoint实现了OAuth 2.0 协议,可以用原生的http 请求它,这里我们用Identity Mode 的client library,它封装了协议的交互的API,直接调用就行。

     //discovery endpoint from metadata
     var client = new HttpClient();
     var disco = await client.GetDiscoveryDocumentAsync("https://localhost:5001");
     if (disco.IsError)
     {
           Console.WriteLine(disco.Error);
            return;
     }

      用discovery document返回的信息向IdentityServer发请求获取token再去获取Resource API。

    //Get access token
     var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest()
     {
          Address = disco.TokenEndpoint,
          ClientId = "client",
          ClientSecret = "secret",
          Scope = "api1"
     });

    将token添加到Http authorization header中,请求Resource API

    var apiClient = new HttpClient();
    apiClient.SetBearerToken(tokenResponse.AccessToken);
    var response = await apiClient.GetAsync("https://localhost:6001/api/IdentityServer");
    if (response.IsSuccessStatusCode)
    {
         var content = await response.Content.ReadAsStringAsync();
         Console.WriteLine(JArray.Parse(content));
    }

    测试结果:

     Notes: 现在程序默认是从IdentityServer请求的任何token信息都可以用来访问Resource API。因为Resource API只认证,但并没有检查Authorization scope。

      下面我们加一些逻辑,验证访问Resource API的access token必须包含某些claims才可以,这里可以使用Authorization policy, 在Resource API中添加Authorization中间件:

    services.AddAuthorization(options =>
    {
        options.AddPolicy("ApiScope", policy =>
        {
            policy.RequireAuthenticatedUser();
            policy.RequireClaim("scope", "api1");
        });
    });

    对于这个Policy可以应用到各层次:

    •  globally
    • for all API endpoint
    • for sepcific controller/action

      通常建立作用于所有API endpoint在路由系统里:

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers()
            .RequireAuthorization("ApiScope");
    });

     OK, Client Credential GrantType 方式IdentityServer先说到这里。
     
      Github源码

       

  • 相关阅读:
    站立会议第1天
    博客园用户体验
    风险评估
    寻找正整数中1的个数
    每个小组对本组的意见
    对每个小组的评论和建议
    每日scrum(六)
    每日scrum(五)
    分析电脑控制的丹佛机场行李系统
    每日scrum(四)
  • 原文地址:https://www.cnblogs.com/qindy/p/14558075.html
Copyright © 2020-2023  润新知