1 添加 apiscope
2 添加 apiresource
添加api名為“client_credentials_apis”的apiresource,並把作用域“client_credentials_apis.IdentityUserController.scope”和“client_credentials_apis.WeatherForecastController.scope”添加到該apiresource中
3 在 ids 添加客戶端
添加客戶端,添加客戶端密鑰,設置授權類型(比如 客戶端憑證方式),並至少設置一個 自定義的 apiscope(如添加 client_credentials_apis.WeatherForecastController.scope);token類型默認為 jwt。
4 客戶端獲取 token並使用 該token訪問api資源
接下來給客戶端添加 client_credentials_apis.IdentityUserController.scope ,重新訪問結果如下:
再給客戶端添加 client_credentials_apis.WeatherForecastController.scope,重新訪問結果如下
客戶端添加作用域如下圖:
5 相關代碼
5.1 api資源端代碼如下:
配置如下:
namespace Resources_Https { public class Config { /// <summary> /// identity server 地址 /// </summary> public const string IdentityServerUri = "https://localhost:44310"; /// <summary> /// reference tokens 的 clientId /// </summary> public const string ApiName = "client_credentials_apis"; /// <summary> /// reference tokens 的 clientSecret /// </summary> public const string ApiSecret = "123456"; } }
startup.cs 代碼如下:
using IdentityModel.AspNetCore.OAuth2Introspection; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.OpenApi.Models; namespace Resources_Https { 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) { // nuget 安裝 Microsoft.AspNetCore.Authentication.JwtBearer // jwt tokens services.AddAuthentication(OAuth2IntrospectionDefaults.AuthenticationScheme) .AddJwtBearer("Bearer", options => { options.Authority = Config.IdentityServerUri; // 設置 https options.RequireHttpsMetadata = true; options.Audience = Config.ApiName; // 支持 jwt 和 reference 兩種 token // if token does not contain a dot, it is a reference token options.ForwardDefaultSelector = context => "Introspection"; }); // reference tokens services.AddAuthentication("Introspection") .AddOAuth2Introspection("Introspection", options => { options.Authority = Config.IdentityServerUri; // this maps to the API resource name and secret options.ClientId = Config.ApiName; // api 名 options.ClientSecret = Config.ApiSecret; // 配置的 api 秘鑰 }); // 策略授權 services.AddAuthorization(options => { // client allowedscope 包含 client_credentials_apis.WeatherForecastController.scope 才能訪問 options.AddPolicy("WeatherForecastController", policy => policy.RequireScope("client_credentials_apis.WeatherForecastController.scope") ); options.AddPolicy("IdentityUserController", policy => policy.RequireScope("client_credentials_apis.IdentityUserController.scope") ); }); services.AddControllers(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "Resources_Https", Version = "v1" }); }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Resources_Https v1")); } app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } } }
TestController代碼:
[ApiController] [Route("[controller]/[action]")] [Authorize] public class TestController : ControllerBase { public IActionResult Ping() { return new JsonResult(new { code = 0, msg = "TestController pong" }); } }
IdentityUserController 代碼:
[ApiController] [Route("[controller]/[action]")] [Authorize(Policy = "IdentityUserController")] public class IdentityUserController : ControllerBase { [HttpGet] public IActionResult Ping() { return new JsonResult(new { code = 0, msg = "IdentityUserController pong" }); } [HttpGet] public IActionResult GetClaims() { var claims = User.Claims.ToList(); var id = User.Identity as ClaimsIdentity; var claim = id.FindFirst(JwtClaimTypes.Subject); return new JsonResult(claims); } }
WeatherForecastController 代碼:
[ApiController] [Route("[controller]/[action]")] [Authorize(Policy = "WeatherForecastController")] public class WeatherForecastController : ControllerBase { [HttpGet] public IActionResult Ping() { return new JsonResult(new { code = 0, msg = "WeatherForecastController pong" }); } }
5.2 客戶端代碼
配置代碼:
public class Config { /// <summary> /// identity server 地址 /// </summary> public const string IdentityServerUri = "https://localhost:44310"; /// <summary> /// 受保護的api地址 /// </summary> public const string ResourceUri = "https://localhost:6001"; public const string ClientId = "ClientCredentials_1_ClientId"; public const string ClientSecret = "511536EF-F270-4058-80CA-1C89C192F69A"; public const string GrantType = "client_credentials"; }
獲取token和訪問資源代碼:
/// <summary> /// 使用 HttpClient 通過客戶端憑證方式獲取token與資源 /// 適用場景:一般用於服務端應用與服務端應用交互 /// 請求token鏈接格式:{idsServer}/connect/token?client_id={}&client_secret={}&grant_type=client_credentials /// </summary> public class HttpClient_ClientCredentials { public static void Run() { // 先獲取 access token var token_res = string.Empty; string postData = $"client_id={Config.ClientId}&client_secret={Config.ClientSecret}&grant_type={Config.GrantType}"; using (var httpClient = new HttpClient()) { using (HttpContent httpContent = new StreamContent(new MemoryStream(Encoding.UTF8.GetBytes(postData)))) { httpContent.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); token_res = httpClient.PostAsync($"{Config.IdentityServerUri}/connect/token", httpContent).Result.Content.ReadAsStringAsync().Result; } } // 使用 token 訪問資源 if (!string.IsNullOrEmpty(token_res)){ using(HttpClient getClient = new HttpClient()) { getClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + JObject.Parse(token_res)["access_token"].ToString()); // 有token就能訪問 var apiRes1 = getClient.GetStringAsync($"{Config.ResourceUri}/Test/Ping").Result; // 有token就能訪問且 client allowedscope 包含 client_credentials_apis.IdentityUserController.scope 才能訪問 var apiRes2 = getClient.GetStringAsync($"{Config.ResourceUri}/IdentityUser/Ping").Result; // 有token就能訪問且 client allowedscope 包含 client_credentials_apis.WeatherForecastController.scope 才能訪問 var res_res3 = getClient.GetStringAsync($"{Config.ResourceUri}/WeatherForecast/Ping").Result; } } } }
參考資源
https://blog.csdn.net/ma_jiang/article/details/107120049