Windows 10 | 1909 |
Visual Studio Community 2019 | 16.5.5 |
.Net Core | 3.1.202 |
IdentityServer4 | 3.1.3 |
IdentityServer4.AccessTokenValidation | 3.0.1 |
1,建立授权Server
1.1 创建空白Asp.Net Core Web项目
1.2 修改Debug方式
修改Properties => launchSettings.json如下:
{
"profiles": {
"IdentityServer4Demo": {
"commandName": "Project",
"launchBrowser": false,
"applicationUrl": "http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
此步骤可做可不做,只是方便debug输出信息
1.3 Nuget引用IdentityServer4
建议别引用最新的Preview版本,虽然编译没问题,但是实际运行的时候总是提示invalid scope
1.4 创建Config类
public class Config
{
/// <summary>
/// 定义要保护的资源
/// </summary>
/// <returns></returns>
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("api1","MyApi"),
new ApiResource("ocelot","test ocelot")
};
}
/// <summary>
/// 定义授权客户端
/// </summary>
/// <returns></returns>
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client(){
ClientId="client",//客户端的标识,要惟一的
AllowedGrantTypes=GrantTypes.ResourceOwnerPassword,//授权方式,必须要用户名和密码
ClientSecrets=
{
new Secret("secret".Sha256())
},
//如果要获取refresh_tokens ,必须在scopes中加上OfflineAccess
AllowedScopes=//定义这个客户端可以访问的API资源数组
{ "api1"
//IdentityServerConstants.StandardScopes.OfflineAccess
}
//AllowOfflineAccess=true// 主要刷新refresh_token
}
};
}
}
GrantTypes是一个枚举类型,指出客户端如何与IdentityServer交互,参见:IdentityServer4【Topic】之授权类型
1.5 创建ResourceOwnerPasswordValidator类
//自定义用户验证
public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
public Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
if (context.UserName == "test" && context.Password == "test")
{
context.Result = new GrantValidationResult(
subject: context.UserName,
authenticationMethod: OidcConstants.AuthenticationMethods.Password);
}
else
{
//验证失败
context.Result = new GrantValidationResult(
TokenRequestErrors.InvalidGrant,
"invalid custom credential"
);
}
return Task.FromResult(0);
}
}
1.6 修改Startup.cs文件
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
//注入IdentityServer服务
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddResourceOwnerValidator<ResourceOwnerPasswordValidator>();//注入自定义登录验证
}
public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//添加认证中间件
app.UseIdentityServer();
}
}
1.7 验证IdentityServer运行成功
Postman get数据:http://localhost:5000/.well-known/openid-configuration
1.8 获取token
Postman post数据:http://localhost:5000/connect/token
2,集成IdentityServer4到Web API
2.1 创建Asp.Net Core Web API 项目
2.2 修改Debug方式
跟1.2步骤一致,但是端口更改为5001
2.3 Nuget引用IdentityServer4.AccessTokenValidation
2.4 修改Setup.cs文件
//在ConfigureServices添加认证服务器信息
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = "http://localhost:5000";//授权服务器地址
options.RequireHttpsMetadata = false;//不需要https
options.ApiName = "api1";
});
}
//在Configure方法中添加认证服务中间件
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthentication();//在Configure方法中添加认证服务中间件
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
2.5 在需要验证授权的Controller或者Method上增加[Authorize]特性
[Authorize]//
[ApiController]
[Route("[controller]")]
//Asp.Net Core Web API 自动生成的示例Controller
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
2.6 测试
没有获取token直接发送请求,将收到401 Unauthorized响应
如果加上1.8步骤获取的token再发送求情,则能够收到正确的信息