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

如何为基于Identity的MVC应用添加JWT认证以支持原生移动应用

在ASP.NET Core Identity MVC应用中添加JWT认证支持原生客户端

核心思路

无需引入第三方中间件,直接基于现有Identity体系扩展JWT认证能力,同时保留原MVC的Cookie认证,实现双认证模式共存,不用大幅重写现有代码。


步骤1:配置JWT认证服务

  1. 安装必要NuGet包:

    Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
    Install-Package System.IdentityModel.Tokens.Jwt
    
  2. 在Program.cs中添加JWT认证配置(保留原Cookie认证):

    var builder = WebApplication.CreateBuilder(args);
    
    // 保留原有Identity配置
    builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();
    
    // 读取JWT配置参数
    var jwtSettings = builder.Configuration.GetSection("JwtSettings");
    var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings["SecretKey"]));
    
    // 配置双认证模式:Cookie用于MVC网页,JWT用于原生客户端
    builder.Services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    .AddCookie()
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = jwtSettings["Issuer"],
            ValidAudience = jwtSettings["Audience"],
            IssuerSigningKey = securityKey
        };
    });
    
    // 可选:创建授权策略,允许Cookie和JWT两种方式访问API
    builder.Services.AddAuthorization(options =>
    {
        options.AddPolicy("AllowDualAuth", policy =>
        {
            policy.AuthenticationSchemes.Add(CookieAuthenticationDefaults.AuthenticationScheme);
            policy.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);
            policy.RequireAuthenticatedUser();
        });
    });
    
  3. 在appsettings.json中添加JWT配置项:

    "JwtSettings": {
        "SecretKey": "your-strong-secret-key-at-least-16-characters",
        "Issuer": "your-app-domain",
        "Audience": "native-client-audience",
        "ExpirationMinutes": 60
    }
    

步骤2:添加登录端点生成JWT

创建API控制器处理原生客户端登录请求,复用Identity的用户验证逻辑:

[ApiController]
[Route("api/auth")]
public class AuthController : ControllerBase
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly IConfiguration _configuration;

    public AuthController(UserManager<IdentityUser> userManager, IConfiguration configuration)
    {
        _userManager = userManager;
        _configuration = configuration;
    }

    [HttpPost("login")]
    public async Task<IActionResult> Login([FromBody] LoginRequest request)
    {
        // 用Identity验证用户名密码
        var user = await _userManager.FindByNameAsync(request.Username);
        if (user == null || !await _userManager.CheckPasswordAsync(user, request.Password))
        {
            return Unauthorized("用户名或密码错误");
        }

        // 组装JWT声明信息
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.NameIdentifier, user.Id),
            new Claim(ClaimTypes.Name, user.UserName)
        };

        // 可选:添加用户角色声明
        var roles = await _userManager.GetRolesAsync(user);
        claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));

        // 生成JWT令牌
        var jwtSettings = _configuration.GetSection("JwtSettings");
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings["SecretKey"]));
        var signingCreds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var token = new JwtSecurityToken(
            issuer: jwtSettings["Issuer"],
            audience: jwtSettings["Audience"],
            claims: claims,
            expires: DateTime.Now.AddMinutes(Convert.ToDouble(jwtSettings["ExpirationMinutes"])),
            signingCredentials: signingCreds);

        return Ok(new
        {
            Token = new JwtSecurityTokenHandler().WriteToken(token),
            Expiration = token.ValidTo
        });
    }
}

// 登录请求数据模型
public class LoginRequest
{
    public string Username { get; set; }
    public string Password { get; set; }
}

步骤3:保护API端点

根据需求选择认证方式保护接口:

  1. 仅允许原生客户端用JWT访问:

    [ApiController]
    [Route("api/protected")]
    [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
    public class ProtectedDataController : ControllerBase
    {
        // 接口逻辑
    }
    
  2. 同时允许MVC网页(Cookie)和原生客户端(JWT)访问:

    [ApiController]
    [Route("api/shared")]
    [Authorize(Policy = "AllowDualAuth")]
    public class SharedDataController : ControllerBase
    {
        // 接口逻辑
    }
    

原生客户端使用流程

  1. 向POST /api/auth/login发送JSON请求,携带用户名密码:
    {
        "Username": "example-user",
        "Password": "example-pass123"
    }
    
  2. 验证通过后,获取返回的Token和Expiration字段;
  3. 后续请求在HTTP头中添加Authorization: Bearer {token},即可访问受保护的API端点。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 14:47:23