博客
关于我
Identity Server4 笔记
阅读量:307 次
发布时间:2019-03-01

本文共 7531 字,大约阅读时间需要 25 分钟。

一. 角色

1. 身份认证服务器

身份认证服务器是一个向客户端发送安全令牌的软件。它的主要功能包括:

  • 保护资源:确保只有授权用户能够访问受保护的API。
  • 身份验证:使用本地帐户或外部身份提供商(如微信登录)验证用户身份。
  • 会话管理:提供单点登录功能,管理用户会话。
  • 客户端管理:认证并管理客户端应用程序。
  • 令牌发布:向客户端发布身份令牌(Identity Token)和访问令牌(Access Token)。
  • 令牌验证:验证客户端提交的令牌,确保其合法性。

身份认证服务器主要支持以下协议:

  • OpenID Connect:提供身份验证和单点登录功能。
  • OAuth 2.0:用于客户端认证和资源访问。

2. 用户

用户是使用客户端的人,通过身份认证服务器获取访问令牌,从而能够访问受保护的API。

3. 客户端

客户端是请求身份认证服务器获取令牌的软件,用于认证用户(获取身份令牌)或访问资源(获取访问令牌)。客户端必须先注册于身份认证服务器,才能请求令牌。常见类型包括:

  • 机密客户端:运行在服务端,例如Web应用程序,使用客户端密钥进行认证。
  • 公开客户端:运行在客户端设备,例如移动应用或原生应用,通常用于隐式流(Implicit Flow)。

4. 资源

资源是被保护的API或身份数据。每个API有一个唯一的名称,客户端使用该名称指定要访问的API。

5. 身份令牌(Identity Token)

身份令牌表示身份认证完成的结果,至少包含用户的身份信息及权限信息。它通常用于验证用户身份。

6. 访问令牌(Access Token)

访问令牌用于获取API访问权限。客户端通过提交访问令牌向受保护API进行认证,令牌包含客户端和使用者的信息。

二. 客户端凭据的认证方式

在没有用户参与的程序中,客户端使用客户端凭据(Client Credentials)进行认证。这种方式不涉及用户交互,完全依赖于程序的配置。

1. 建立 IdentityServer4

配置IdentityServer4的步骤如下:

  • 定义API和客户端:在Config类中定义API和客户端。
  • public static class Config{    public static IEnumerable
    ApiScopes { return new List
    { new ApiScope("api1", "My API") }; } public static IEnumerable
    Clients { return new List
    { new Client { ClientId = "client", AllowedGrantTypes = GrantTypes.ClientCredentials, ClientSecrets = { new Secret("secret".Sha256()) }, AllowedScopes = { "api1" } } }; }}
    1. 配置服务:在Startup类中添加IdentityServer4服务,并配置客户端。
    2. public class Startup : IStartup{    public IConfiguration Configuration { get; set; }    public Startup(IConfiguration configuration)    {        Configuration = configuration;    }    public void ConfigureServices(IServiceCollection services)    {        services.AddControllers();        var builder = services.AddIdentityServer()            .AddInMemoryApiScopes(Config.ApiScopes)            .AddInMemoryClients(Config.Clients)            .AddDeveloperSigningCredential();    }    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)    {        if (env.IsDevelopment())        {            app.UseDeveloperExceptionPage();        }        app.UseRouting();        app.UseAuthentication();        app.UseAuthorization();        app.UseEndpoints(endpoints =>        {            endpoints.MapControllers();        });    }}
      1. 运行命令:使用命令行运行IdentityServer4。
      2. dotnet run --urls http://*:5001

        2. 建立受保护的API

      3. 定义受保护的API:在IdentityController中使用[Authorize]属性标记受保护的端点。
      4. [ApiController]public class IdentityController : ControllerBase{    [Authorize]    [HttpGet("identity")]    public IActionResult Get()    {        return new JsonResult(from c in User.Claims select new { c.Type, c.Value });    }    [Authorize]    [HttpGet("test")]    public string Getst()    {        return "受保护的API访问成功";    }}
        1. 配置服务:在Startup类中添加认证和授权服务。
        2. public void ConfigureServices(IServiceCollection services){    services.AddControllers();    services.AddAuthentication("Bearer")        .AddJwtBearer("Bearer", options =>        {            options.Authority = "https://localhost:5001";            options.TokenValidationParameters = new TokenValidationParameters            {                ValidateAudience = false            };        });    services.AddAuthorization(options =>    {        options.AddPolicy("ApiScope", policy =>        {            policy.RequireAuthenticatedUser();            policy.RequireClaim("scope", "api1");        });    });}public void Configure(IApplicationBuilder app, IWebHostEnvironment env){    if (env.IsDevelopment())    {        app.UseDeveloperExceptionPage();    }    app.UseRouting();    app.UseAuthentication();    app.UseAuthorization();    app.UseEndpoints(endpoints =>    {        endpoints.MapControllers();    });}
          1. 客户端获取令牌:使用HttpClient获取令牌。
          2. public class Program{    public static async Task Main(string[] args)    {        var client = new HttpClient();        var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5001");        if (disco.IsError)        {            Console.WriteLine($"连接失败:{disco.Error}");            return;        }        var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest        {            Address = disco.TokenEndpoint,            ClientId = "client",            ClientSecret = "secret",            Scope = "api1"        });        if (tokenResponse.IsError)        {            Console.WriteLine($"token返回错误:{tokenResponse.Error}");            return;        }        Console.WriteLine(tokenResponse.Json);        var apiClient = new HttpClient();        apiClient.SetBearerToken(tokenResponse.AccessToken);        var response = await apiClient.GetAsync("http://localhost:6001/test");        if (!response.IsSuccessStatusCode)        {            Console.WriteLine(response.StatusCode);            Console.WriteLine("访问失败");        }        else        {            var content = await response.Content.ReadAsStringAsync();            Console.WriteLine("访问成功");            Console.WriteLine(content);        }        Console.ReadLine();    }}

            3. 保护WPF客户端

            WPF客户端涉及用户交互,使用密码grant类型进行认证。

          3. 流程
            • 浏览器将请求传给用户代理。
            • 用户代理连接身份认证服务器,获取授权代码。
            • 用户同意后,浏览器将授权代码提交至身份认证服务器,获取访问令牌。
            • 客户端使用访问令牌访问受保护API。
            1. 刷新令牌:在MVC控制器中添加令牌刷新功能。
            2. private async Task
              RenewTokensAsync(){ var client = new HttpClient(); var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000"); if (disco.IsError) { throw new Exception(disco.Error); } var refreshToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.RefreshToken); var tokenResponse = await client.RequestRefreshTokenAsync(new RefreshTokenRequest { Address = disco.TokenEndpoint, ClientId = "mvc client", ClientSecret = "mvc secret", Scope = "api1 openid profile email phone address", GrantType = OpenIdConnectGrantTypes.RefreshToken, RefreshToken = refreshToken }); if (tokenResponse.IsError) { throw new Exception(tokenResponse.Error); } var expiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(tokenResponse.ExpiresIn); var tokens = new[] { new AuthenticationToken { Name = OpenIdConnectParameterNames.IdToken, Value = tokenResponse.IdentityToken }, new AuthenticationToken { Name = OpenIdConnectParameterNames.AccessToken, Value = tokenResponse.AccessToken }, new AuthenticationToken { Name = OpenIdConnectParameterNames.RefreshToken, Value = tokenResponse.RefreshToken }, new AuthenticationToken { Name = "expires_at", Value = expiresAt.ToString("o", CultureInfo.InvariantCulture) } }; await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme); currentAuthenticateResult.Properties.StoreTokens(tokens); await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, currentAuthenticateResult.Principal, currentAuthenticateResult.Properties); return tokenResponse.AccessToken;}

              三. 混合流

              混合流结合了隐式流和客户端凭据流的优点,适用于需要获取身份令牌和访问令牌的场景。

            3. 客户端类型
              • 机密客户端:适用于服务端应用,如MVC。
              • 公开客户端:适用于桌面应用、移动应用等。
              1. 返回类型
                • response_type = code Id_token
                • response_type = code token
                • response_type = code id_token token

                四. 角色和策略

              2. 角色
                • 定义多个角色,如管理员和普通用户。
                • 每个角色可以包含多个用户。
                1. 策略
                  • 基于角色:使用[Authorize(Roles = "管理员,普通用户")]限制访问权限。
                  • 基于策略:定义自定义策略,如RequireClaim(JwtClaimTypes.FamilyName, "Smith")

                  五. 使用混合流保护客户端

                  混合流允许客户端在不直接暴露访问令牌的情况下,通过后端通道获取令牌,从而保护敏感信息。

                  参考文献

                  [1] [2] [3] [4]

    转载地址:http://xuwl.baihongyu.com/

    你可能感兴趣的文章
    nopcommerce商城系统--文档整理
    查看>>
    NOPI读取Excel
    查看>>
    NoSQL&MongoDB
    查看>>
    NoSQL介绍
    查看>>
    NoSQL数据库概述
    查看>>
    Notadd —— 基于 nest.js 的微服务开发框架
    查看>>
    NOTE:rfc5766-turn-server
    查看>>
    Notepad ++ 安装与配置教程(非常详细)从零基础入门到精通,看完这一篇就够了
    查看>>
    Notepad++在线和离线安装JSON格式化插件
    查看>>
    notepad++最详情汇总
    查看>>
    notepad++正则表达式替换字符串详解
    查看>>
    notepad如何自动对齐_notepad++怎么自动排版
    查看>>
    Notes on Paul Irish's "Things I learned from the jQuery source" casts
    查看>>
    Notification 使用详解(很全
    查看>>
    NotImplementedError: Cannot copy out of meta tensor; no data! Please use torch.nn.Module.to_empty()
    查看>>
    NotImplementedError: Could not run torchvision::nms
    查看>>
    Now trying to drop the old temporary tablespace, the session hangs.
    查看>>
    nowcoder—Beauty of Trees
    查看>>
    np.arange()和np.linspace()绘制logistic回归图像时得到不同的结果?
    查看>>
    np.power的使用
    查看>>