02-07 .net core 3.1 使用 Ocelot搭建api网关添加鉴权认证

前言

通过使用IdentityServer4给网关添加鉴权认证可以提高api的安全性。

在阅读本文之前,建议先阅读 02-01 .net core 3.1 使用 Ocelot搭建api网关

一、添加一个webApi项目,命名为IdentityServer(随意)
1、 然后用nuget安装IdentityServer4 包(如何操作不再赘述)

在这里插入图片描述

2、添加一个Config.cs(类名随意)
using IdentityServer4;
using IdentityServer4.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace IdentityServer
{
    public static class Config
    {
        public static IEnumerable<IdentityResource> GetIdentityResourceResources()
        {
            return new List<IdentityResource>
            {
                new IdentityResources.OpenId(), //必须要添加,否则报无效的scope错误
            };
        }
        // scopes define the API resources in your system
        public static IEnumerable<ApiResource> GetApiResources()
        {
            //可访问的API资源(资源名,资源描述)
            return new List<ApiResource>
            {
                new ApiResource("FirstApi", "FirstApi"),
                new ApiResource("SecondApi", "SecondApi")
            };
        }

        public static IEnumerable<Client> GetClients()
        {
            return new List<Client>
            {
                new Client
                {
                    ClientId = "firstClient", //访问客户端Id,必须唯一
                    //使用客户端授权模式,客户端只需要clientid和secrets就可以访问对应的api资源。
                    AllowedGrantTypes = GrantTypes.ClientCredentials,
                    ClientSecrets =
                    {
                        new Secret("secret".Sha256())
                    },
                    AllowedScopes = { "FirstApi", IdentityServerConstants.StandardScopes.OpenId,IdentityServerConstants.StandardScopes.Profile }
                },
                new  Client
                {
                    ClientId = "secondClient",
                    ClientSecrets = new [] { new Secret("secret".Sha256()) },
                    AllowedGrantTypes = GrantTypes.ClientCredentials,
                    AllowedScopes = { "SecondApi", IdentityServerConstants.StandardScopes.OpenId,IdentityServerConstants.StandardScopes.Profile }
                }
            };
        }
    }
}

因为我有两个下游api,所以我添加两个api资源和客户端

3、修改IdentityServer项目Startup.cs中的ConfigureServices方法
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    //添加鉴权
    services.AddIdentityServer()
            .AddDeveloperSigningCredential()
            .AddInMemoryApiResources(Config.GetApiResources())
            .AddInMemoryClients(Config.GetClients());
}

如图
在这里插入图片描述

4、在IdentityServer项目Startup.cs中的Configure方法的最前面加上app.UseIdentityServer();也就是方法http管道中在这里插入图片描述
5、在IdentityServer项目添加一个TokenApiController,用来获取token

这里需要注意的是2.2.0及以下版本IdentityServer4和最新版的获取token的方式有所不同
(1)2.2.0以上版本IdentityServer4获取token的方式之一

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using IdentityModel.Client;
using IdentityServer4.Models;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;

namespace IdentityServer
{
    /// <summary>
    /// 获取token
    /// </summary>
    public class TokenApiController : ApiController
    {
        [HttpPost,HttpGet]
        public string GetToken([FromBody]RequestTokenModel model)
        {
            var httpClient = new HttpClient();
            var disco = httpClient.GetDiscoveryDocumentAsync(new DiscoveryDocumentRequest
            {
                Address = $"{ Request.Scheme }://{Request.Host}"
            }).Result;
            if (disco.IsError)
            {
                throw new Exception(disco.Error);
            }
            var tokenResponse = httpClient.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
            {
                Address = disco.TokenEndpoint,
                ClientId = model.ClientId,
                ClientSecret = model.ClientSecret,
                Scope = model.Scope
            });
            var json = tokenResponse.Result.Json;
            return json.ToString();
        }
    }

    /// <summary>
    /// 请求model
    /// </summary>
    public class RequestTokenModel
    {
        /// <summary>
        /// IdentityServer项目Config.cs的GetClients方法中配置的访问客户端Id
        /// </summary>
        public string ClientId { get; set; }

        /// <summary>
        /// IdentityServer项目Config.cs的GetClients方法中配置的ClientSecrets
        /// </summary>
        public string ClientSecret { get; set; }

        /// <summary>
        /// IdentityServer项目Config.cs的GetClients方法中配置的scope
        /// </summary>
        public string Scope { get; set; }
    }
}

(2)2.2.0及以下版本IdentityServer4获取token方式,仅供参考

public class TokenController : Controller
{
    public async Task<JObject> Get()
    {
        var disco = await DiscoveryClient.GetAsync($"{Request.Scheme}://{Request.Host}");
        if(disco.IsError)
        {
            Console.WriteLine(disco.Error);
            return null;
        }
		string clientId = "client";
		string clientSecret  = "secret";
		string scope = "FirstApi";
        var tokenClient = new TokenClient(disco.TokenEndpoint, clientId , clientSecret );
        var tokenResponse = await tokenClient.RequestClientCredentialsAsync(scope );
        if(tokenResponse.IsError)
        {
            Console.WriteLine(tokenResponse.Error);
            return null;
        }
        return tokenResponse.Json;
    }
}

请求api:http://localhost:5003/TokenApi/GetToken测试一下,如图说明已经拿到客户端firstApi的token了
在这里插入图片描述
如果http获取参数方式是FromForm,则以下面方式传参
在这里插入图片描述
在这里插入图片描述

二、给网关(WebApiGateway项目)集成IdentityServer
1、使用nuget给WebApiGateway项目安装IdentityServer4.AccessTokenValidation包,用于验证IdentityServer4中的JWT和引用令牌
2、在 WebApiGateway项目Startup.cs 的 ConfigureServices 中注册两个认证方案,在Configure 中配置IdentityServer服务。

注意:注册认证方案最好是加在ConfigureServices方法的最前面,配置IdentityServer服务最好是放在app.UseOcelot();后面

public void ConfigureServices(IServiceCollection services)
{
    //注册认证方案
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddIdentityServerAuthentication("firstApiKey", x =>
            {
                x.ApiName = "FirstApi"; // 这个是认证服务(IdentityServer项目)Config.cs 的 GetApiResources方法中配置的api名称
                x.Authority = "http://localhost:5003";  // 这个是认证服务(IdentityServer项目)的地址
                x.RequireHttpsMetadata = false;
            }).AddIdentityServerAuthentication("secondApiKey", y =>
            {
                y.ApiName = "SecondApi";   // 这个是认证服务(IdentityServer项目)Config.cs 的 GetApiResources方法中配置的api名称
                y.Authority = "http://localhost:5003";  // 这个是认证服务(IdentityServer项目)的地址
                y.RequireHttpsMetadata = false;
            });

    //添加Ocelot,注意configuration.json的路径,我本身就放在了根路径下
    services.AddOcelot(new ConfigurationBuilder()
        .AddJsonFile("configuration.json", true, true).Build())
        .AddPolly() //添加 Ocelot.Provider.Polly 实现熔断
        .AddCacheManager(x => x.WithDictionaryHandle());  // 添加 Ocelot.Cache.CacheManager 实现缓存
    
    services.AddControllers();
}


public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    //配置使用Ocelot
    app.UseOcelot();

    //配置IdentityServer服务
    app.UseAuthorization();

    app.UseHttpsRedirection();

    app.UseRouting();

    app.UseAuthorization();

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

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

3、修改WebApiGateway项目的Oeclot配置文件configuration.json,在“ReRoutes”中的下游api对象中添加
//授权信息
"AuthenticationOptions": {
  "AuthenticationProviderKey": "firstApiKey",  //这个key就是在startup.cs中注册的key,不要写错了
  "AllowedScopes": []
}

如图:
在这里插入图片描述
Ocelot会去检查ReRoutes是否配置了AuthenticationOptions节点。如果有会根据配置的认证方案进行身份认证。如果没有则不进行身份认证。

  • AuthenticationProviderKey :是刚才注册的认证方案。
  • AllowedScopes :是 AllowedScopes中配置的授权访问范围。

还需要在configuration.json添加IdentityServer api的网关配置

	// IdentityServer api,用来获取token
    {
      "UpstreamPathTemplate": "/identity/{controller}/{action}",
      "DownstreamPathTemplate": "/{controller}/{action}",
      "UpstreamHttpMethod": [ "GET", "POST", "DELETE", "PUT" ],
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 5003
        }
      ]
    },

如图
在这里插入图片描述

4、编译并启动WebApiGateway、IdentityServer、FirstApi、SecondApi四个项目

(1)访问http://localhost:5000/first/firstApi/getmessage,可以看到返回状态为未授权
在这里插入图片描述
(2)先访问http://localhost:5000/identity/TokenApi/GetToken
在这里插入图片描述
(3)获取到token后,在将token加到http://localhost:5000/first/firstApi/getmessage认证中,如图
在这里插入图片描述
(4)换下参数,拿到SecondApi的token
在这里插入图片描述
(5)访问SecondApi
在这里插入图片描述
至此IdentityServer4鉴权的基本用法就尝试成功了。

本系列源码地址

参考文章

IdentityModel最新文档
.Netcore 2.0 Ocelot Api网关教程(5)- 认证和授权
.Net Core使用Ocelot网关(二) -鉴权认证
IdentityServer4客户端获取Token的方法

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
.NET 5 中,你可以使用 ASP.NET Core 中的中间件来捕获 Ocelot 中的 polly.Timeout.TimeoutRejectedException 异常。具体来说,你可以在 Startup.Configure 方法中添加一个中间件来处理异常。 以下是一个简单的示例,演示如何在 ASP.NET Core 5 应用程序中捕获 Ocelot 中的 polly.Timeout.TimeoutRejectedException 异常: ```csharp public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseExceptionHandler(errorApp => { errorApp.Run(async context => { var exception = context.Features.Get<IExceptionHandlerFeature>().Error; if (exception is Polly.Timeout.TimeoutRejectedException) { // 处理 TimeoutRejectedException 异常 await context.Response.WriteAsync("请求超时"); } else { // 处理其他异常 await context.Response.WriteAsync(exception.Message); } }); }); // 添加 Ocelot 中间件 app.UseOcelot().Wait(); } ``` 在上面的示例中,我们使用了 UseExceptionHandler 中间件来捕获异常。当发生异常时,中间件会进入 Run 方法中,并通过 Get<IExceptionHandlerFeature>() 方法获取异常信息。如果异常是 polly.Timeout.TimeoutRejectedException 异常,我们就可以对其进行特殊处理,例如返回一个错误信息给用户。如果异常是其他类型的异常,我们则可以进行其他的处理。 需要注意的是,在使用 Ocelot 中间件时,要确保它在异常处理中间件之前被添加,这样才能确保异常能被正确地捕获和处理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值