Swagger Open Api Identity 授權訪問

一般使用Swagger 都是開放式閱讀API文件,但有些特殊情況,並不想受任何人都可以閱讀API文件
所以需要增加登入驗證,才給予授權訪問該文件

環境

  1. VS2022
  2. Net 6
  3. WebApi專案

方向

  1. 製作登入
  2. 使用ClaimsIdentity存放Cookies
  3. 檢查是否有權限訪問SwaggerUI,無則導向登入

步驟

Program中修改 

builder.Services.AddControllers

builder.Services.AddControllersWithViews();

新增LoginController並在該Class上加入

[Route("[controller]")]
[ApiExplorerSettings(IgnoreApi = true)]
[Route("[controller]")]
[ApiExplorerSettings(IgnoreApi = true)]
public class LoginController : Controller
{
    public IActionResult Index()
    {
        var dd = HttpContext;
        return View(new ViewModels.Index());
    }

    /// <summary>
    /// 登入POST
    /// </summary>
    /// <returns></returns>
    [HttpPost]
    public async Task<IActionResult> Index(ViewModels.Index model)
    {
        var claims = new List<Claim>
        {
            new Claim("Authorized", model.Account!),
        };
        var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);

        await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity),
        new AuthenticationProperties()
        {
            IsPersistent = true,
            ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(30),
            AllowRefresh = true
        });

        return Redirect("/swagger");
    }
}

建立ViewModel

public class Index
{
    [Required(ErrorMessage = "帳號未填寫")]
    public string? Account { get; set; }

    [Required(ErrorMessage = "密碼未填寫")]
    public string? Password { get; set; }
}

建立View

<html lang="zh-TW">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>登入</title>
</head>
<body >
     <form action="Login" method="post">         
          <input Id="Account" name="Account" type="text" placeholder="Account">
          <input Id="Password" name="Password" type="password" placeholder="Password">
          <button type="submit">
              <span>登入</span>
          </button>
     </form>
</body>
</html>

Program中增加

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(option =>
{
    option.LoginPath = new PathString("/Login/Index");
    option.LogoutPath = new PathString("/Login/Index");
    option.AccessDeniedPath = new PathString("/Login/Index");
    option.ExpireTimeSpan = TimeSpan.FromMinutes(30);

    option.Cookie.HttpOnly = true;
});

app.UseAuthentication();

建立SwaggerInterceptor 檢查訪問權限

public class SwaggerInterceptor
{
    private readonly RequestDelegate _next;

    public SwaggerInterceptor(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        var uri = context.Request.Path.ToString().ToUpper();
        if (uri.StartsWith("/swagger".ToUpper()))
        {
            var role = context.User.Claims.FirstOrDefault(x => x.Type == "Authorized")?.Value;
            if (role == null || role == null)
            {
                context.Response.Redirect("/Login");
                return;
            }
        }

        await _next.Invoke(context);
    }
}

Program中增加UseMiddleware
注意需擺在UseAuthentication下方,UseSwagger上方,執行順序問題

app.UseAuthentication();

app.UseMiddleware<SwaggerInterceptor>();

app.UseSwagger();
app.UseSwaggerUI();

建立完成後會看到系統導向登入而非預設的SwaggerUI


登入成功後才可進入SwaggerUI


資料參考來源

  1. StackOverFlow