You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在.NET Core 6 Razor Pages中正确使用[Authorize]特性?

解决Web项目中[Authorize]特性生效的方案

一、核心原因:原方案的问题

你之前的代码仅将Token添加到当前请求的响应头,但重定向到Employees页面时,新请求不会携带这个响应头的Token;同时Web项目未配置对应的身份验证方案,默认的[Authorize]基于Cookie身份验证,没有合法的身份Cookie就无法触发验证逻辑。


二、分步实现方案

1. 配置Web项目的Cookie身份验证

在.NET 6+的Program.cs(或旧版的Startup.cs)中添加Cookie身份验证服务和中间件:

var builder = WebApplication.CreateBuilder(args);

// 添加Razor Pages服务
builder.Services.AddRazorPages();

// 配置Cookie身份验证
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.LoginPath = "/Login"; // 未认证时自动跳转的登录页
        options.ExpireTimeSpan = TimeSpan.FromHours(2); // Cookie有效期
        options.AccessDeniedPath = "/AccessDenied"; // 无权限时跳转页面(可选)
    });

var app = builder.Build();

// 中间件顺序必须严格遵循:先认证,再授权
app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();
app.Run();

2. 登录成功后创建Web端身份Cookie

修改Web项目登录页面的代码,在获取API Token后,同时创建Web端的身份凭证,让[Authorize]能识别已登录用户:

var userName = Request.Form["UserName"].ToString();
var password = Request.Form["Password"].ToString();
var login = new Models.Login();
login.UserName = userName;
login.Password = password;

var apiUrl = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build().GetSection("AppSettings")["BaseUrl"] +
    "/api/Authenticate/Authenticate";
using (WebClient client = new WebClient())
{
    client.Headers[HttpRequestHeader.ContentType] = "application/json";
    string Json = JsonConvert.SerializeObject(login);
    var response = client.UploadString(apiUrl, Json);
    var result = JsonConvert.DeserializeObject<Models.LoginResponseModel>(response);
    
    if(result.code != 200)
    {
        InvalidLogin = true;
        return this.Page();
    }
    else
    {
        // 1. 存储API Token到Session,供后续调用API使用
        HttpContext.Session.SetString("Token", result.Message);
        
        // 2. 创建Web端身份凭证,触发Cookie验证
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Name, userName),
            // 可按需添加角色、用户ID等其他声明信息
        };
        var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
        var principal = new ClaimsPrincipal(identity);
        
        // 登录用户,自动生成身份Cookie
        await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
        
        return new RedirectToPageResult("/Employees");
    }
}

3. 完善Logout逻辑

在Web项目中添加注销逻辑,同时清除Web端身份Cookie和Session中的API Token,如需同步API端注销,需通过Token调用API的Logout接口:

public async Task<IActionResult> OnGetLogout()
{
    // 清除Web端身份Cookie
    await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    
    // 清除Session中的API Token
    var token = HttpContext.Session.GetString("Token");
    HttpContext.Session.Remove("Token");
    
    // 调用API的Logout接口(需API端根据Token处理注销,而非Session)
    if (!string.IsNullOrEmpty(token))
    {
        var apiUrl = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build().GetSection("AppSettings")["BaseUrl"] +
            "/api/Authenticate/Logout";
        using (WebClient client = new WebClient())
        {
            client.Headers.Add("Authorization", $"Bearer {token}");
            client.DownloadString(apiUrl);
        }
    }
    
    return RedirectToPage("/Login");
}

4. 优化API调用的Token携带

为避免每次调用API都手动添加Token,可封装一个自动携带Token的WebClient:

public class ApiWebClient : WebClient
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    
    public ApiWebClient(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
        Headers[HttpRequestHeader.ContentType] = "application/json";
        
        var token = _httpContextAccessor.HttpContext.Session.GetString("Token");
        if (!string.IsNullOrEmpty(token))
        {
            Headers.Add("Authorization", $"Bearer {token}");
        }
    }
}

// 在Program.cs中注册服务
builder.Services.AddHttpContextAccessor();
builder.Services.AddTransient<ApiWebClient>();

后续调用API时,直接注入ApiWebClient即可自动携带Token。


三、API端Logout的修正

由于Web和API是独立项目,Session不共享,API端的Logout不应依赖Session,需改为通过请求头的Token识别用户,将Token加入注销黑名单(如用Redis存储),后续API收到该Token时拒绝请求。

示例API Logout接口:

[Route("[action]")]
[HttpGet]
public IActionResult Logout()
{
    // 从请求头获取Token
    if (Request.Headers.TryGetValue("Authorization", out var authHeader) && authHeader.ToString().StartsWith("Bearer "))
    {
        var token = authHeader.ToString().Substring(7);
        // 将Token加入黑名单(示例:用Redis存储过期时间)
        // _redis.SetString(token, "invalid", TimeSpan.FromHours(2));
    }
    return Ok();
}

内容的提问来源于stack exchange,提问作者user123456

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 14:00:53