Tips:本篇已加入,.Net core 3.1 使用IdentityServer4 實現 OAuth2.0 --閱讀目錄 可點擊查看更多相關文章。html
本篇會詳細刨析客戶端模式的流程圖,羅列一下此模式的利弊,適用場景。最後會用代碼進行實現,此外還會額外參雜一些相關知識的彩蛋。 前端
客戶端模式(Client Credentials Grant) 是全部模式中最簡單的模式,因此我會盡量的把 一些細小的,可能後面文章也會涉及到的點,都概括在此篇中。api
對於一些名詞解釋,忘記的同窗能夠看一下以前一篇文章,打開傳送門 服務器
業務場景:用戶使用客戶端模式去訪問一個資源(咱們能夠理解成這個資源是查看數據)app
上圖是用戶訪問資源的總體流程,其實除了灰色的部分,認證的流程不同,用戶訪問資源,資源服務器是否受權客戶端資源都是同樣的,因此以後的文章中我會只畫出灰色的認證流程部分你們要注意一下。async
用文字描述一下 客戶端模式的流程就是:oop
1.客戶端 訪問受權服務器,提交clientid,或者clientSecret(密碼能夠提交也能夠不提交,具體由代碼控制)post 2.受權服務器 校驗clientid (和 clientSecret)是否能夠經過身份認證,經過後返回 訪問令牌(此令牌能夠訪問資源服務器)ui |
咱們按照官方文檔的實現步驟,實現一遍代碼。this
官方實現的步驟以下:
|
若是是 使用IdentityServer4 4.x版本的話,就算按照以上步驟實現完,你會發現請求訪問老是401。
要注意一下!!! ID4 4.x版本須要定義api的做用域,以前的版本做用域不定義的話都是默認與資源名稱相同。 在這裏我額外的加了一個步驟:
|
接下來 咱們上手操做一遍:
先看一下目錄結構:
前面步驟說到的 定義api資源,定義做用域,定義客戶端,咱們所有寫在 5000站點項目裏的 Config文件。
你們想一下,咱們要保護資源總要告訴認證受權服務器,保護資源的名稱,哪些客戶端能夠看到(而客戶端權限是做用在做用域上的,做用域又將api資源分組歸類,那麼這樣也就定義了哪些客戶端能夠看到哪些api資源了)
public static class Config { /// <summary> /// Defining an API Resource /// </summary> public static IEnumerable<ApiResource> Apis => new List<ApiResource> { new ApiResource("api1", "My API") }; /// <summary> /// Defining the scope /// </summary> /// <returns></returns> public static IEnumerable<ApiScope> ApiScopes => new ApiScope[] { new ApiScope("api1"), }; /// <summary> /// Defining the client /// </summary> public static IEnumerable<Client> Clients => new List<Client> { new Client { ClientId = "client", // no interactive user, use the clientid/secret for authentication AllowedGrantTypes = GrantTypes.ClientCredentials, // secret for authentication ClientSecrets = { new Secret("secret".Sha256()) }, // scopes that client has access to AllowedScopes = { "api1" } } }; }
接下來要完成的步驟就是: Configuring IdentityServer 配置ID4 服務端
修改一下 IdentityServer項目中的 Startup 文件,爲了讓認證受權服務啓動的時候能知道 資源相關的定義,而且啓用一下 ID4中間件。
public class Startup { // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { //程序啓動的時候加載 受保護的api資源,api做用域,客戶端定義 var builder = services.AddIdentityServer() .AddInMemoryApiResources(Config.Apis) .AddInMemoryApiScopes(Config.ApiScopes) .AddInMemoryClients(Config.Clients); } // 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.UseRouting(); app.UseIdentityServer();//使用ID4中間件 app.UseEndpoints(endpoints => { endpoints.MapGet("/", async context => { await context.Response.WriteAsync("Hello World!"); }); }); } }
ID4 提供了 內存級別讀取資源,做用域和客戶端的方法 .AddInMemoryXXXXX() 上面案例中咱們都是讀取的 Config類中的寫死的資源,固然也能夠從配置文件中讀取,
至此,認證受權的服務器所有完工。接下去咱們寫一個最基本的api,在ResourceApi中咱們新增一個 IdentityController。
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace ResourceApi.Controllers { [Authorize] public class IdentityController : Controller { [HttpGet] public IActionResult Get() { return new JsonResult(from c in User.Claims select new { c.Type, c.Value }); } } }
咱們給 IdentityController 加一個 用戶身份驗證 標籤 [Authorize] 這樣進來的請求就須要通過 .netcore的 身份認證。
咱們修改一下 ResourceApi的 Startup文件 :
|
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) { services.AddMvc().AddNewtonsoftJson(options => { // 忽略循環引用 options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // 不使用駝峯 options.SerializerSettings.ContractResolver = new DefaultContractResolver(); // 設置時間格式 options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; // 如字段爲null值,該字段不會返回到前端 // options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; }); //將認證服務註冊到容器中,而且配置默認token的方案名爲 Bearer services.AddAuthentication("Bearer") .AddJwtBearer("Bearer", options => { options.Authority = "http://localhost:5000";//受權服務器地址 options.RequireHttpsMetadata = false; options.Audience = "api1";//token能訪問的 受衆羣體(這個定義要和受權服務器定義的資源名稱同樣) }); } // 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.UseHttpsRedirection(); app.UseAuthentication(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "api/{controller}/{action}"); }); } }
到這裏,受權服務器代碼也好了,資源api服務也好了。剩下的就是 客戶端代碼了,咱們看一下 VisitorClient這個控制檯應用: