aspnetcore最最簡單的介面許可權認證

2023-05-31 12:01:51

五月一眨眼就過去,就當湊個數吧。

場景:

一個小小的專案,需要一個後臺,就展示幾個列表,連使用者表、角色表等都不需要設計。

之前有寫過identityserver4和jwt4的demo

(exercisebook/IdentityServer4&Serilog at main · liuzhixin405/exercisebook · GitHub

exercisebook/授權/授權一/JwtToken at main · liuzhixin405/exercisebook · GitHub),

但是這樣一個專案中上這些肯定是大材小用。

微軟提供的還有一個就是cookie,既然夠簡單,那麼什麼也不用設計,儘量做到最簡單,而且後期還可以通過表設計來完善這個的後臺登入模組。

首先我們要實現的就是介面程式碼的授權:

  [Authorize]
    [ApiController]
    [Route("[controller]")]
    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;
        }

        [Authorize(Roles = "Admin")] // 要求"Admin"角色的授權
        [HttpGet(Name = "GetWeatherForecast")]
        public IEnumerable<WeatherForecast> Get()
        {
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }

上面的特性使得WeatherForecastController介面需要許可權才能存取,而GetWeatherForecast介面需要Admin角色就可以存取。

下面就通過program來設定及安全中心和授權策略:

using Microsoft.AspNetCore.Authentication.Cookies;

namespace auth_cookie
{
    /// <summary>
    /// 一個簡單的Cookie身份驗證和授權範例
    /// </summary>
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // Add services to the container.

            builder.Services.AddControllers();
            // 設定Cookie身份驗證
            builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(options =>
                {
                    options.Cookie.Name = "YourAuthCookie"; // 設定Cookie的名稱
                    options.LoginPath = "/api/Auth/Login"; // 設定登入路徑
                });

            // 設定授權服務
            builder.Services.AddAuthorization(options =>
            {
                options.AddPolicy("RequireAdminRole", policy => policy.RequireRole("Admin"));
            });
            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();

            var app = builder.Build();

            // Configure the HTTP request pipeline.
            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

            app.UseHttpsRedirection();
            app.UseAuthentication(); // 啟用身份驗證
            app.UseAuthorization(); // 啟用授權


            app.MapControllers();

            app.Run();
        }
    }
}

上面的程式碼夠簡單的吧,核心程式碼也就這幾行。指定預設的scheme為cookie,寫好註釋。指定策略RequireAdminRole,要求角色Admin,都可以很靈活的多設定,通過資料庫,組態檔等。

 // 設定Cookie身份驗證
            builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(options =>
                {
                    options.Cookie.Name = "YourAuthCookie"; // 設定Cookie的名稱
                    options.LoginPath = "/api/Auth/Login"; // 設定登入路徑
                });

            // 設定授權服務
            builder.Services.AddAuthorization(options =>
            {
                options.AddPolicy("RequireAdminRole", policy => policy.RequireRole("Admin"));
            });

這樣不算晚,還需要一個登入和登出的授權的介面,而且介面路徑寫好了,/api/Auth/Login

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;

namespace auth_cookie.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class AuthController : ControllerBase
    {
        //[HttpPost("login")]
        [HttpGet("login")] //方便測試
        public async Task<IActionResult> Login(string username, string password)
        {
            // 執行驗證使用者名稱和密碼的邏輯
            //這裡可以和存到資料庫的使用者和密碼進行比對
            if(username != "admin" && password != "123456")
            {
                return BadRequest("Invalid username or password");
            }
            // 如果驗證成功,建立身份驗證Cookie
            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.Name, username),
                new Claim(ClaimTypes.Role, "Admin") // 新增使用者角色
            };

            var claimsIdentity = new ClaimsIdentity(
                claims, CookieAuthenticationDefaults.AuthenticationScheme);

            await HttpContext.SignInAsync(
                CookieAuthenticationDefaults.AuthenticationScheme,
                new ClaimsPrincipal(claimsIdentity),
                new AuthenticationProperties());

            return Ok("Login successful");
        }

        //[HttpPost("logout")]
        [HttpGet("logout")]
        public async Task<IActionResult> Logout()
        {
            await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            return Ok("Logout successful");
        }
    }
}

上面的核心程式碼根據我們設定的做的設定,一一對應,要不然就無權存取WeatherForecastController了:

 var claims = new List<Claim>
            {
                new Claim(ClaimTypes.Name, username),
                new Claim(ClaimTypes.Role, "Admin") // 新增使用者角色
            };

            var claimsIdentity = new ClaimsIdentity(
                claims, CookieAuthenticationDefaults.AuthenticationScheme);

下面看看效果,存取 :https://localhost:7066/WeatherForecast,會自動跳轉到https://localhost:7066/api/Auth/Login?ReturnUrl=%2FWeatherForecast

我們指定一下使用者名稱和密碼 https://localhost:7066/api/Auth/Login?username=admin&password=123456ReturnUrl=%2FWeatherForecast

再來存取 https://localhost:7066/WeatherForecast

退出登入,https://localhost:7066/api/auth/logout

再來存取 

https://localhost:7066/WeatherForecast

配合前端的後臺管理,一個很簡單的後臺登陸就這樣ok了。

原始碼:

exercisebook/授權/授權三/auth_cookie at main · liuzhixin405/exercisebook · GitHub