客戶端模式(Client Credentials Grant)

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

官方實現的步驟以下:

  • Defining an API Resource   定義api資源
  • Defining the client                 定義客戶端
  • Configuring IdentityServer     配置ID4 服務端
  • Adding an API                       新增一個api
  • Creating the client                 建立一個客戶端
  • Calling the API                      調用api

 

 

 

 

 

 

若是是 使用IdentityServer4   4.x版本的話,就算按照以上步驟實現完,你會發現請求訪問老是401。

要注意一下!!!

ID4 4.x版本須要定義api的做用域,以前的版本做用域不定義的話都是默認與資源名稱相同。

在這裏我額外的加了一個步驟:

  • Defining the scope  定義做用域

 

 

 

 

 

 

接下來 咱們上手操做一遍:

先看一下目錄結構:

 

 前面步驟說到的 定義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文件 :

  • AddAuthentication adds the authentication services to DI and configures Bearer as the default scheme.
  • UseAuthentication adds the authentication middleware to the pipeline so authentication will be performed automatically on every call into the host.
  • UseAuthorization adds the authorization middleware to make sure, our API endpoint cannot be accessed by anonymous clients.

 

 

 

    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這個控制檯應用:

相關文章
相關標籤/搜索