博客
关于我
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/

    你可能感兴趣的文章
    Objective-C实现Eulers TotientFunction欧拉函数算法(附完整源码)
    查看>>
    Objective-C实现eulers totient欧拉方程算法(附完整源码)
    查看>>
    Objective-C实现EulersTotient欧拉方程算法(附完整源码)
    查看>>
    Objective-C实现eval函数功能(附完整源码)
    查看>>
    Objective-C实现even_tree偶数树算法(附完整源码)
    查看>>
    Objective-C实现Exceeding words超词(差距是ascii码的距离) 算法(附完整源码)
    查看>>
    Objective-C实现exchange sort交换排序算法(附完整源码)
    查看>>
    Objective-C实现ExponentialSearch指数搜索算法(附完整源码)
    查看>>
    Objective-C实现extended euclidean algorithm扩展欧几里得算法(附完整源码)
    查看>>
    Objective-C实现ExtendedEuclidean扩展欧几里德GCD算法(附完整源码)
    查看>>
    Objective-C实现external sort外排序算法(附完整源码)
    查看>>
    Objective-C实现Factorial digit sum阶乘数字和算法(附完整源码)
    查看>>