欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Asp Net Core開(kāi)發(fā)筆記之如何給SwaggerUI加上登錄保護(hù)功能

 更新時(shí)間:2024年05月22日 09:28:25   作者:程序設(shè)計(jì)實(shí)驗(yàn)室  
這篇文章主要介紹了Asp Net Core開(kāi)發(fā)筆記之如何給SwaggerUI加上登錄保護(hù)功能,本文以我最近在開(kāi)發(fā)的單點(diǎn)認(rèn)證項(xiàng)目(IdentityServerLite)為例給大家詳細(xì)講解,需要的朋友可以參考下

前言

在 SwaggerUI 中加入登錄驗(yàn)證,是我很早前就做過(guò)的,不過(guò)之前的做法總感覺(jué)有點(diǎn)硬編碼,最近 .Net8 增加了一個(gè)新特性:調(diào)用 MapSwagger().RequireAuthorization 來(lái)保護(hù) Swagger UI ,但官方的這個(gè)功能又像半成品一樣,只能使用 postman curl 之類(lèi)的工具帶上 Authorization header 來(lái)請(qǐng)求,在瀏覽器里打開(kāi)就直接401了 ……

剛好有個(gè)項(xiàng)目需要用到這個(gè)功能,于是我把之前做過(guò)的 SwaggerUI 登錄認(rèn)證中間件拿出來(lái)重構(gòu)了一下。

這次我依然使用 Basic Auth 的方式來(lái)登錄,寫(xiě)了一個(gè)自定義的 SwaggerAuthenticationHandler,通過(guò) Microsoft.AspNetCore.Authentication 提供的擴(kuò)展方法來(lái)實(shí)現(xiàn)登錄。

PS:本文以我最近在開(kāi)發(fā)的單點(diǎn)認(rèn)證項(xiàng)目(IdentityServerLite)為例

配置Swagger

這次我試著不按照寫(xiě)代碼的順序,而是站在使用者的角度來(lái)介紹,也許會(huì)更直觀一些。

編輯 src/IdsLite.Api/Extensions/CfgSwagger.cs 文件 (顧名思義,這是用來(lái)配置Swagger的相關(guān)擴(kuò)展方法)

public static class CfgSwagger {
  public static IServiceCollection AddSwagger(this IServiceCollection services) {
    services.AddSwaggerGen();
    return services;
  }
  public static IApplicationBuilder UseSwaggerWithAuthorize(this IApplicationBuilder app) {
    app.UseMiddleware<SwaggerBasicAuthMiddleware>();
    app.UseSwagger();
    app.UseSwaggerUI();
    return app;
  }
}

其他的都是常規(guī)的配置,重點(diǎn)在于 app.UseMiddleware<SwaggerBasicAuthMiddleware>(); 添加了一個(gè)中間件

SwaggerBasicAuth 中間件

來(lái)編寫(xiě)這個(gè)中間件,代碼路徑 src/IdsLite.Api/Middlewares/SwaggerBasicAuthMiddleware.cs

public class SwaggerBasicAuthMiddleware {
  private readonly RequestDelegate _next;
  public SwaggerBasicAuthMiddleware(RequestDelegate next) {
    _next = next;
  }
  public async Task InvokeAsync(HttpContext context) {
    if (context.Request.Path.StartsWithSegments("/swagger")) {
      var result = await context.AuthenticateAsync(AuthSchemes.Swagger);
      if (!result.Succeeded) {
        context.Response.Headers["WWW-Authenticate"] = "Basic";
        context.Response.StatusCode = StatusCodes.Status401Unauthorized;
        return;
      }
    }
    await _next(context);
  }
}

主要邏輯在 InvokeAsync 方法里

判斷當(dāng)前地址以 /swagger 開(kāi)頭的話,就進(jìn)入身份認(rèn)證流程,如果配置了其他 SwaggerUI 地址,記得同步修改這個(gè)中間件的配置,或者做成通用的配置,避免硬編碼。

這里使用了 Microsoft.AspNetCore.Authentication.AuthenticationHttpContextExtensions 提供的擴(kuò)展方法 context.AuthenticateAsync("Scheme Name") 來(lái)驗(yàn)證身份 (具體的 scheme 我們后面會(huì)實(shí)現(xiàn))

如果驗(yàn)證失敗的話,返回 401 ,同時(shí)添加響應(yīng)頭 WWW-Authenticate:Basic ,這樣就能在瀏覽器里彈出輸入用戶名和密碼的提示框了。

AuthenticationScheme

在注冊(cè) Authentication 服務(wù)的時(shí)候,可以添加一些其他的 scheme

PS: AspNetCore 的這套 Identity 確實(shí)有點(diǎn)復(fù)雜,用了這么久感覺(jué)還是沒(méi)有系統(tǒng)的認(rèn)識(shí)這個(gè) Identity 框架

注冊(cè)服務(wù)

注冊(cè)服務(wù)的代碼大概是這樣

services
  .AddAuthentication(options => {
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme;
  })
  .AddJwtBearer(...)
  .AddScheme<AuthenticationSchemeOptions, SwaggerAuthenticationHandler>(AuthSchemes.Swagger, null);

AddScheme 方法可以添加各種類(lèi)型的認(rèn)證方案,這里添加了一個(gè)自定義的認(rèn)證方案 SwaggerAuthenticationHandler,后面的參數(shù)是方案的名稱(chēng)和選項(xiàng)。

為了避免硬編碼,我寫(xiě)了個(gè)靜態(tài)類(lèi)

public static class AuthSchemes {
  public const string Swagger = "SwaggerAuthentication";
}

SwaggerAuthenticationHandler

接下來(lái)實(shí)現(xiàn)這個(gè)自定義的認(rèn)證方案

其實(shí)就是把 Basic Authenticate 和固定用戶名和密碼結(jié)合在一起

不過(guò)為了不在代碼里硬編碼,我把用戶名和密碼放在配置里了,通過(guò)注入 IOption<T> 的方式獲取。也可以放在數(shù)據(jù)庫(kù)里,通過(guò) EFCore 之類(lèi)的去讀取。

public class SwaggerAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions> {
  public SwaggerAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) {}
  public SwaggerAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder) : base(options, logger, encoder) {}
  protected override async Task<AuthenticateResult> HandleAuthenticateAsync() {
    if (!Request.Headers.TryGetValue("Authorization", out var value)) {
      return AuthenticateResult.Fail("Missing Authorization Header");
    }
    var config = Context.RequestServices.GetRequiredService<IOptions<IdsLiteConfig>>().Value;
    try {
      var authHeader = AuthenticationHeaderValue.Parse(value);
      var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
      var credentials = Encoding.UTF8.GetString(credentialBytes).Split(":", 2);
      var username = credentials[0];
      var password = credentials[1];
      if (username != config.Swagger.UserName || password != config.Swagger.Password) {
        return AuthenticateResult.Fail("Invalid Username or Password");
      }
      var claims = new[] { new Claim(ClaimTypes.Name, username) };
      var identity = new ClaimsIdentity(claims, Scheme.Name);
      var principal = new ClaimsPrincipal(identity);
      var ticket = new AuthenticationTicket(principal, Scheme.Name);
      return AuthenticateResult.Success(ticket);
    }
    catch {
      return AuthenticateResult.Fail("Invalid Authorization Header");
    }
  }
}

try 里面的代碼,就是從 request header 里讀取 basic auth 的用戶名和密碼(通常是 Base64 編碼過(guò)的),解碼之后判斷是否正確,然后返回認(rèn)證結(jié)果。

擴(kuò)展

還可以集成 OpenIDConnect 和 OAuth ,我還沒(méi)有實(shí)踐,詳情見(jiàn)參考資料。

小結(jié)

既要在項(xiàng)目發(fā)布后訪問(wèn) SwaggerUI ,又要保證一定的安全性,本文提供的思路或許是一種比較簡(jiǎn)單又有效的解決方案。

參考資料

到此這篇關(guān)于Asp Net Core開(kāi)發(fā)筆記之如何給SwaggerUI加上登錄保護(hù)功能的文章就介紹到這了,更多相關(guān)Asp Net Core SwaggerUI登錄保護(hù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論