IdentityServer4在.Net Core 3.1中应用(客户端授权模式)


前言

这里只是记录自己学习IdentityServer4的过程,不讲述原理。 如要学习原理,请查询其他相关资料。


一、配置IdentityServer4

1.1 安装程序包

我们这里将IdentityServer4服务器作为一个项目,所有的认证和授权都是从这个项目开始的,Access Token也是从这里发出
的,我们要将IdentityServer4安装到授权和认证的服务器项目中。

使用Visual Studio 2019创建一个名称为 “Samlpe.IdentityServer” 的基于.Net Core 3.1的 ASP.NET Core Web API 项目,用于IdentityServer4的服务器。
创建项目
在这里插入图片描述
项目创建完成后,在此项目中通过NuGet安装IdentityServer4。安装的IdentityServer4的版本为4.1.2
在这里插入图片描述

1.2 配置IdentityServer4

在“Samlpe.IdentityServer”此项目中,需要对认证和授权进行配置。添加一个名称为Config的类文件,用于配置IdentityServer4。

Config.cs 代码如下:

using IdentityServer4.Models;
using IdentityServer4.Test;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Sample.IdentityServer
{
    public class Config
    {

        /// <summary>
        /// 配置ApiResource
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<ApiResource> ApiResources()
        {
            return new List<ApiResource>() {

                //将多个具体的ApiScope归为一个ApiResource。可将多个Api范围进行分组,
                //这样分的好处是对Api资源分的更细,在授权时,可更精细的控制。
               new ApiResource("Sample","IdentityServer4学习用例"){

                    Scopes={ "sample_api","demo_api" }
               }
            };

        }


        /// <summary>
        /// 设置具体的Api的范围
        /// </summary>
        public static IEnumerable<ApiScope> ApiScopes()
        {
            return new List<ApiScope>(){

               new ApiScope("sample_api","Sample Api"),
               new ApiScope("demo_api","Demo Api")

            };
        }

        /// <summary>
        /// 配置客户端应用
        /// </summary>
        public static IEnumerable<Client> Clients()
        {
            return new List<Client> {

                //客户端模式
                new Client{
                //客户端ID
                ClientId = "sample_api",

                //认证秘钥
                ClientSecrets = { new Secret("sample_client_secret".Sha256()) },

                //认证模式:设置为客户端模式
                AllowedGrantTypes = GrantTypes.ClientCredentials,

                //设置客户端有权访问的范围
                AllowedScopes = { "sample_api" }
                },
            };
        }
    }
}

在最新的IdentityServer4版本中,多了一个ApiScope的配置,用于配置多个API范围。

而在ApiResource中,将多个Api范围进行了分组,这样分组的好处是API资源分的更细,在授权时,可更精细的控制。

  1. ApiResources()方法用于将多个ApiScope归为一组,成为API资源,其中包括多个ApiScope。
  2. ApiScopes()方法定义多个具体的ApiScope,在ApiResources中必须引用的这里定义的ApiScope。
  3. Clients()方法定了多个客户端相关的认证和授权信息,用于在IDS4服务器上接受这些客户端,从而完成授权和认证。

1.3 注册DI容器

接下来,在Startup.ConfigureServices()方法中,将IdentityServer4组件注册到DI容器中。

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            //将IdentityServer注册到DI容器当中
            services.AddIdentityServer()
                .AddDeveloperSigningCredential()   //在开发模式下自动生成JWT的秘钥,实际运行过程中需要自己生成秘钥。
              //.AddSigningCredential()运用自己生成的秘钥。
                .AddInMemoryApiResources(Config.ApiResources())//注册ApiResource
                .AddInMemoryApiScopes(Config.ApiScopes())// 注册API的范围
                .AddInMemoryClients(Config.Clients());//注册Api的客户端
        }

1.4 添加中间件

接下来,还需要将IdentityServe4的中间件添加到管道中:

  public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            //这个必须在UseRouting和UseEndpoints中间。如果IdentityServer服务端和API端要写在一起,
            //那么这个必须在UseAuthorization和UseAuthentication的上面。
            app.UseIdentityServer();  

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

1.5 修改项目配置信息

默认情况下,ASP.NET Core项目都会监听 5000 端口。这个项目不做修改,需要在launchSettings.json文件中修改启动类型。
在这里插入图片描述
launchBrowser都修改为False,并删除launchUrl设置的默认启动页。

1.6 测试发现文档

现在,Smaple.IdentityServer修改完成后,编译一下项目,直接按Control+F5启动项目。
在这里插入图片描述
认证服务器的项目已经跑起来了。在浏览器中输入如下地址访问IdentityServer4的发现文档:

http://localhost:5000/.well-known/openid-configuration
在这里插入图片描述
此时,已经访问到了IdentityServer4的发现文档,使用这些文档可以提供认证和授权服务。

二、配置受保护的API项目

2.1 创建API项目

Sample解决方案中,添加一个名称为Sample.WebApi的ASP.NET Core WebAPI项目,用于创建API操作资源,充当API资源服务器。

创建一个基于ASP.NET Core 3.1的WebApi项目。
在这里插入图片描述
现在,WebApi项目已经创建完成了,在此项目中添加API操作,用于操作Api资源。

2.2 配置认证授权服务器

接下来,要在API资源服务器上配置IdentityServer4服务器,也就是要与IdentityServer4服务器关联起来,让客户端传过来的AccessToken能够在API资源服务器上识别并向客户端返回响应的API资源。

配置IdentityServer4服务器,需要在API资源服务器上安装Microsoft.AspNetCore.Authentication.JwtBearer包。
在这里插入图片描述
这里是基于ASP.NET Core 3.1的框架,JwtBearer包要选择3.1.14版本的。如果创建的是ASP.NET Core 5.0的框架,则选择5.0.5版本即可。

接下来,在Startup.cs类ConfigureServices()方法中,将身份验证服务添加到DI并配置Bearer为默认方案,需要添加

Microsoft.IdentityModel.Tokens 命名空间。。

代码如下:

  public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();

            //注册身份验证服务
            services.AddAuthentication("Bearer").AddJwtBearer("Bearer", options =>
            {
                options.Authority = "http://localhost:5000"; //设置颁发Token的服务器地址
                options.RequireHttpsMetadata = false; //设置不为Https请求
                options.TokenValidationParameters = new TokenValidationParameters //不验证jwt的aud信息
                {
                    ValidateAudience = false
                };
            });

            //认证授权服务
            services.AddAuthorization(options =>
            {
                //添加一个授权范围,这个名字可以随便起
                options.AddPolicy("ApiScope", polict =>
                {
                    //鉴定用户
                    polict.RequireAuthenticatedUser();
                    polict.RequireClaim("scope", "sample_api");
                });
            });
        }

通过上面的代码,就建立了与IdentityServer服务器的通信。

2.3 配置认证中间件

在API资源服务器上的Startup.Configure()方法中,将身份验证中间件添加到管道中,以便对主机的每次调用都将自动执行身份验证。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            //身份验证中间件 (身份验证必须在授权的前面)
            app.UseAuthentication();

            //授权验证中间件
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                //.RequireAuthorization("ApiScope") 将授权应用到当前Api所有的端点上。
            });
        }

此代码中的身份验证中间件app.UseAuthentication()必须放在app.UseAuthorization()的前面,app.UseRouting()的后面。

2.4 保护API资源

在ASP.NET Core框架中,要保护API资源,需要在控制类中,添加 [Authorize] 特性。

[Authorize] 特性存在于 Microsoft.AspNetCore.Authorization 命名空间中。

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;

namespace Sample.WebApi.Controllers
{
    [ApiController]
    [Route("[controller]")]
    [Authorize("ApiScope")]
    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();
        }
    }
}

这里引用的是WebAPI项目中自带的天气预报控制器。此时,我们直接再直接访问这个控制器则会出现401错误。

如上图所属,发现我的源代码中写的是 [Authorize(“ApiScope”)] 而不是 [Authorize] 。这与我们在API资源访问服务器的Startup.Configure()方法中定义的认证授权策略相关,我们可以使用定义的授权范围去限制哪些API操作可以被访问。如果指定的策略名称与API资源服务器上备案的策略名称不一致,则是无法访问的。

[Authorize(“ApiScope”)] 中括号中的名称必须与Startup.Configure()中定义的认证授权服务中起的别名一致。
在这里插入图片描述

2.5 修改端口号

这里将API资源服务器的端口改为 6000,以免发生端口冲突的问题。并将launchBrowser改为 False。
在这里插入图片描述
上面的工作完成后,编译一下项目,保证没有错误。

三、Postman测试

3.1 启动项目

首先将Sample.IdentityServerSample.WebApi两个项目都运行起来。然后在Postman里面进行模拟测试。

在这里插入图片描述
在这里插入图片描述

3.2 获取Token

项目启动起来后,我们在Postman里面请求Sample.IdentityServer服务器。获取到Token数据。
获取Token的地址为IdentityServer4发现文档中的token_endpoint所携带的地址。

在这里插入图片描述

我们创建一个Post请求,在请求体Body中加入client_idclient_secretgrant_type三个参数,对应的值为配置客户端时设置的值。
在这里插入图片描述
接下来,我们开始发送请求,获取Token。
在这里插入图片描述
如上图所示,我们已经顺利的拿到了Token。

3.3 携带Token请求资源服务器

下来我们将携带Token去请求Sample.WebApi API资源服务器。
在这里插入图片描述
除了上图的方式外,我们还可以在Header头部信息中加入Authorization,在参数中写入Bearer+空格+Token
在这里插入图片描述
我们携带Token开始发送请求,获取API资源服务器中的数据。
在这里插入图片描述
在这里插入图片描述
两种方式,我们均拿到了API资源服务器返回的数据。此时表明我们整体流程是没有问题的。

四、配置客户端

4.1 简介

经过Postman测试之后,已经表明我们整体上没有问题。我们接下来使用.Net Core客户端来测试开发的IdentityServer4服务器和API资源服务器。

4.2 创建控制台应用程序

Sample解决方案中,添加一个Sample.Client的.Net Core控制台应用程序。
在这里插入图片描述
使用这个控制台应用程序通过IdentityServer4服务器获取AccessToken,然后再拿着这个AccessToken去访问API资源服务器获取数据。

4.3 安装 IdentityModel 包

客户端要能访问IdentityServer认证服务器,需要在客户端应用程序安装IdentityModel包。
在这里插入图片描述

4.4 请求方法

在客户端的Program.cs中编写请求代码。具体的代码如下所示:

using System;
using System.Net.Http;
using System.Threading.Tasks;
using IdentityModel.Client;
using Newtonsoft.Json.Linq;

namespace Sample.Client
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var client = new HttpClient();

            var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000");

            if (disco.IsError)
            {
                Console.WriteLine(disco.Error);
                return;
            }

            var tokenRequest = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
            {

                Address = disco.TokenEndpoint,
                ClientId = "sample_api",
                ClientSecret = "sample_client_secret"
            });

            Console.WriteLine("IdentityServer4服务器返回的结果 : {0}", tokenRequest.Json);

            var apiClient = new HttpClient();

            apiClient.SetBearerToken(tokenRequest.AccessToken);

            var response = await apiClient.GetAsync("http://localhost:6000/WeatherForecast");

            if (!response.IsSuccessStatusCode)
            {
                Console.WriteLine(response.StatusCode);
                return;
            }

            var content = await response.Content.ReadAsStringAsync();

            Console.WriteLine(JArray.Parse(content));
            Console.ReadKey();
        }
    }
}

4.5 整体测试

我们先启动IdentityServer认证服务器和API资源服务器。
在这里插入图片描述
在这里插入图片描述
两个项目启动后,我们接下来启动客户端程序,看是否能拿到和Postman中返回一样的数据。
在这里插入图片描述
如图所示,和Postman中的结果一样。至此,客户端认证模式就已经全部完成了。

如需要源码,请在Gitee上下载:IdentityServer4Demo

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值