客户端模式(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这个控制台应用:

相关文章
相关标签/搜索