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

ASP.NET Core MVC如何通过独立API实现用户认证授权?

完全可以这么做,这种架构能有效解耦认证逻辑和业务系统,还能实现用户数据的统一管理,下面分两部分讲具体实现方式:

一、ASP.NET Core MVC 项目配置(调用独立API完成认证)

1. 自定义登录逻辑

放弃默认Identity直接连接数据库的方式,在登录接口中调用独立认证API验证用户凭证,接收返回的身份信息后生成用户身份并完成登录。

示例代码(AccountController的Login POST方法):

using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using System.Net.Http.Json;

[HttpPost]
public async Task<IActionResult> Login(LoginViewModel model)
{
    if (!ModelState.IsValid) return View(model);

    // 注入HttpClientFactory创建客户端
    var httpClient = _httpClientFactory.CreateClient();
    var loginPayload = new { Username = model.Username, Password = model.Password };
    
    // 调用认证API
    var response = await httpClient.PostAsJsonAsync("https://your-auth-api-domain/api/auth/login", loginPayload);

    if (!response.IsSuccessStatusCode)
    {
        ModelState.AddModelError("", "用户名或密码错误");
        return View(model);
    }

    // 解析API返回的认证结果
    var authResult = await response.Content.ReadFromJsonAsync<AuthResult>();
    
    // 构建用户Claims身份
    var claims = new List<Claim>
    {
        new Claim(ClaimTypes.Name, authResult.Username),
        new Claim(ClaimTypes.Role, authResult.Role)
        // 按需添加其他用户属性作为Claim
    };
    var identity = new ClaimsIdentity(claims, "CustomApiAuth");
    var userPrincipal = new ClaimsPrincipal(identity);

    // 将用户身份保存到Cookie,完成登录
    await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, userPrincipal, new AuthenticationProperties
    {
        IsPersistent = model.RememberMe,
        ExpiresUtc = DateTimeOffset.UtcNow.AddHours(2)
    });

    return RedirectToAction("Index", "Profile");
}

2. 基础配置

  • 在Program.cs中注册HttpClientFactory和Cookie认证:
// 注册HttpClient工厂
builder.Services.AddHttpClient();

// 配置Cookie认证
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.LoginPath = "/Account/Login"; // 未登录时跳转的登录页
        options.AccessDeniedPath = "/Account/AccessDenied"; // 权限不足跳转页
    });

// 启用认证和授权中间件(注意顺序:先认证后授权)
app.UseAuthentication();
app.UseAuthorization();

3. 授权保护页面

在需要授权的Controller或Action上添加[Authorize]特性即可:

[Authorize]
public class ProfileController : Controller
{
    public IActionResult Index()
    {
        // 这里可以通过User.Claims获取用户身份信息
        return View();
    }
}
二、独立认证API的实现

1. 核心认证流程

API需要完成以下步骤:

  • 接收前端(MVC项目)传来的用户名和密码
  • 连接独立用户数据库验证凭证合法性
  • 验证通过后生成身份凭证(比如JWT令牌)或返回用户身份信息
  • 向MVC项目返回认证结果(成功/失败+对应数据)

2. API示例代码

以ASP.NET Core Web API为例,实现登录接口:

首先定义统一的请求/返回模型:

// 登录请求模型
public class LoginRequest
{
    public string Username { get; set; } = string.Empty;
    public string Password { get; set; } = string.Empty;
}

// 认证结果返回模型
public class AuthResult
{
    public string Username { get; set; } = string.Empty;
    public string Role { get; set; } = string.Empty;
    public string Token { get; set; } = string.Empty;
    public int ExpiresIn { get; set; } // 令牌有效期(秒)
}

然后实现AuthController:

using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

[ApiController]
[Route("api/auth")]
public class AuthController : ControllerBase
{
    private readonly IUserRepository _userRepo;
    private readonly IConfiguration _config;

    public AuthController(IUserRepository userRepo, IConfiguration config)
    {
        _userRepo = userRepo;
        _config = config;
    }

    [HttpPost("login")]
    public async Task<IActionResult> Login([FromBody] LoginRequest request)
    {
        // 从独立数据库查询用户
        var user = await _userRepo.GetUserByUsername(request.Username);
        if (user == null || !VerifyPassword(request.Password, user.PasswordHash))
        {
            return Unauthorized(new { Message = "用户名或密码错误" });
        }

        // 生成JWT令牌
        var jwtToken = GenerateJwtToken(user);

        return Ok(new AuthResult
        {
            Username = user.Username,
            Role = user.Role,
            Token = jwtToken,
            ExpiresIn = 7200 // 2小时
        });
    }

    // 生成JWT令牌方法
    private string GenerateJwtToken(User user)
    {
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Name, user.Username),
            new Claim(ClaimTypes.Role, user.Role)
        };

        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:SecretKey"]));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var token = new JwtSecurityToken(
            issuer: _config["Jwt:Issuer"],
            audience: _config["Jwt:Audience"],
            claims: claims,
            expires: DateTime.Now.AddHours(2),
            signingCredentials: creds);

        return new JwtSecurityTokenHandler().WriteToken(token);
    }

    // 密码验证(这里用BCrypt哈希验证,需安装BCrypt.Net NuGet包)
    private bool VerifyPassword(string inputPassword, string storedHash)
    {
        return BCrypt.Net.BCrypt.Verify(inputPassword, storedHash);
    }
}

3. API数据库配置

实现IUserRepository接口,连接独立服务器的数据库(比如用EF Core):

public class UserRepository : IUserRepository
{
    private readonly UserDbContext _dbContext;

    public UserRepository(UserDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task<User> GetUserByUsername(string username)
    {
        return await _dbContext.Users.FirstOrDefaultAsync(u => u.Username == username);
    }
}

在API的Program.cs中配置数据库连接字符串:

builder.Services.AddDbContext<UserDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("UserDatabase")));

// 注册仓储
builder.Services.AddScoped<IUserRepository, UserRepository>();
三、关键注意事项
  • 通信安全:MVC项目和认证API之间必须用HTTPS通信,防止密码、令牌等敏感数据被窃取。
  • 令牌存储:MVC项目推荐将JWT令牌存储在HttpOnly Cookie中,避免XSS攻击。
  • 权限扩展:如果需要细粒度权限控制,可以在API中新增权限验证接口,MVC项目调用该接口判断用户是否具备操作权限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 05:54:58