IdentityServer4专题之五:OpenID Connect及其Client Credentials流程模式
1.基于概念
OAuth2.0与身份认证协议的角色映射
OpenID Connect 这个协议是2014颁发的,基于OAuth2.0,在这个协议中,ID Token会和Access Token一起发回客户端应用,它还提供了一个UserInfo这个端点,通过此端点可以获取用户信息,还提供了一级标识身份的scopes和claims(profile、email、address、phone)
这个协议定义了三个流程:
Identity Server4.0的结构图
2.三种流程模式
IdentityServer上:
在startup.cs页面中ConfiureServices页面中,应将json config 方式改为code config方式。即按如下方式切换注释代码
// in-memory, code config
builder.AddInMemoryIdentityResources(Config.GetIdentityResources());
builder.AddInMemoryApiResources(Config.GetApis());
builder.AddInMemoryClients(Config.GetClients());
// in-memory, json config
//builder.AddInMemoryIdentityResources(Configuration.GetSection("IdentityResources"));
//builder.AddInMemoryApiResources(Configuration.GetSection("ApiResources"));
//builder.AddInMemoryClients(Configuration.GetSection("clients"));
public static class Config
{
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new IdentityResource[]
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
};
}
public static IEnumerable<ApiResource> GetApis()
{
return new ApiResource[]
{
new ApiResource("api1", "My API #1")
};
}
public static IEnumerable<Client> GetClients()
{
return new[]
{
// client credentials flow client
new Client
{
ClientId = "console client",
ClientName = "Client Credentials Client",
AllowedGrantTypes = GrantTypes.ClientCredentials,
ClientSecrets = { new Secret("511536EF-F270-4058-80CA-1C89C192F69A".Sha256()) },
AllowedScopes = {"api1" }
}
};
}
}
客户端控制台程序代码:
static async Task Main(string[] args)
{
//Discovery endpoint
Console.WriteLine("Hello World!");
var client = new HttpClient();
var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000");
if(disco.IsError)
{
Console.WriteLine(disco.Error);
return;
}
//Request access token,客户端必须带有:ClientCredentials
var tokenResponse =await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest {
Address = disco.TokenEndpoint,
ClientId = "console client",
ClientSecret = "511536EF-F270-4058-80CA-1C89C192F69A",
Scope= "api1"
});
if (tokenResponse.IsError)
{
Console.WriteLine(tokenResponse.Error);
return;
}
var apiClient = new HttpClient();
apiClient.SetBearerToken(tokenResponse.AccessToken);
var response = await apiClient.GetAsync("http://localhost:5002/api/values");
if (!response.IsSuccessStatusCode)
{
Console.WriteLine(response.StatusCode);
}
else
{
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
}
}
asp.net core api资源应用:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//使用IdentityServer认证和授权
services.AddMvcCore().AddAuthorization().AddJsonFormatters();
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.Audience = "api1";
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{ //使用identityserver
app.UseAuthentication();
app.UseMvc();
}
}
[Route("api/[controller]")]
[Authorize]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2","value3"};
}
}
总结:Client Credentials这种方式,客户端应用不代表用户,客户端应用本身就相当于是资源所有者;通常用于机器对机器的通信;客户端也需要身份认证。
可采用工具软件监控客户端与服务端的通信:
将获取的access token放到网站https://jwt.io/,进行解码,即可以看到token中包含的许多用用信息。