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

同一Web应用中ASP.NET Core 2 MVC与WebAPI身份认证整合问询

Got it, let's break down how to integrate your MVC Cookie authentication with WebAPI JWT auth so your Vue components in Razor views can call the API seamlessly without forcing users to log in twice. I've tackled this exact scenario before—here's the play-by-play:

1. Generate a JWT Token When Users Log Into MVC

First, when a user logs in via your MVC AccountController, you'll want to create a JWT token alongside setting the auth cookie. This way, the Vue frontend can grab the token and use it for API calls.

Here's how to modify your Login action:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model)
{
    // Your existing user validation logic here
    if (ModelState.IsValid && await _userManager.CheckPasswordAsync(user, model.Password))
    {
        var claimsPrincipal = await _signInManager.CreateUserPrincipalAsync(user);
        
        // Set the MVC auth cookie (your existing code)
        await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal);

        // Generate JWT token
        var jwtToken = GenerateJwtToken(claimsPrincipal);

        // Option 1: Store token in a non-HttpOnly cookie (Vue can read this)
        Response.Cookies.Append("JwtToken", jwtToken, new CookieOptions
        {
            HttpOnly = false, // Allow JS access
            SameSite = SameSiteMode.Strict,
            Secure = Environment.IsProduction(), // Use HTTPS in prod
            Expires = DateTime.UtcNow.AddHours(1)
        });

        // Option 2: Pass token to Razor view, then save to localStorage in Vue
        ViewData["JwtToken"] = jwtToken;

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

    // Handle invalid login
    ModelState.AddModelError("", "Invalid login attempt");
    return View(model);
}

// Helper method to generate JWT
private string GenerateJwtToken(ClaimsPrincipal principal)
{
    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:SecretKey"]));
    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

    var token = new JwtSecurityToken(
        issuer: Configuration["Jwt:Issuer"],
        audience: Configuration["Jwt:Audience"],
        claims: principal.Claims,
        expires: DateTime.UtcNow.AddHours(1),
        signingCredentials: creds);

    return new JwtSecurityTokenHandler().WriteToken(token);
}
2. Configure WebAPI to Accept Both Auth Schemes

Your WebAPI currently only accepts JWT, but we need it to recognize either JWT (for external clients) or MVC cookies (for Vue calls, if you go that route) — or just enforce JWT but let Vue pass the token we generated.

Update your Startup.cs to register both auth schemes:

public void ConfigureServices(IServiceCollection services)
{
    // Existing MVC setup
    services.AddMvc();

    // Configure authentication
    services.AddAuthentication(options =>
    {
        // Default to cookie auth for MVC, but we'll specify JWT for API when needed
        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    .AddCookie(options =>
    {
        options.LoginPath = "/Account/Login";
        options.SlidingExpiration = true;
    })
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = Configuration["Jwt:Issuer"],
            ValidAudience = Configuration["Jwt:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:SecretKey"]))
        };
    });
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // Other middleware (error handling, static files, etc.)

    // Make sure authentication runs before MVC
    app.UseAuthentication();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
        routes.MapRoute(name: "api", template: "api/{controller}/{action}/{id?}");
    });
}

Then, on your WebAPI controllers/actions, you can allow both schemes like this:

[Authorize(AuthenticationSchemes = "Bearer,Cookies")]
[Route("api/[controller]")]
public class MyApiController : ControllerBase
{
    // API actions here
}

This lets the API accept either a Bearer <token> header or the MVC auth cookie.

3. Make Vue Automatically Attach the JWT to API Calls

Now, set up your Vue app to grab the JWT from either the cookie or localStorage, and attach it to every axios request.

Add this to your Vue main.js (or an axios config file):

import axios from 'axios';

// Helper to get cookie value
function getCookie(name) {
    const value = `; ${document.cookie}`;
    const parts = value.split(`; ${name}=`);
    if (parts.length === 2) return parts.pop().split(';').shift();
}

// Attach JWT to all requests
axios.interceptors.request.use(config => {
    const token = getCookie('JwtToken');
    if (token) {
        config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
}, error => Promise.reject(error));

// Make axios available globally in Vue
Vue.prototype.$axios = axios;

If using localStorage:

In your Razor view, add this script before initializing Vue:

<script>
    // Save the token from ViewData to localStorage
    localStorage.setItem('JwtToken', '@ViewData["JwtToken"]');
</script>

Then update the axios interceptor:

axios.interceptors.request.use(config => {
    const token = localStorage.getItem('JwtToken');
    if (token) {
        config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
}, error => Promise.reject(error));
4. Handle Token Expiration with a Refresh Endpoint

To avoid forcing users to log in again when the JWT expires, add a refresh token endpoint that uses the MVC cookie to issue a new JWT:

[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
[Route("api/auth/refresh-token")]
public IActionResult RefreshToken()
{
    // User is already authenticated via cookie, so we can get their claims
    var newToken = GenerateJwtToken(User);
    return Ok(new { Token = newToken });
}

Then update your axios response interceptor to handle 401 errors:

axios.interceptors.response.use(response => response, async error => {
    const originalRequest = error.config;
    // Only retry once for 401s
    if (error.response.status === 401 && !originalRequest._retry) {
        originalRequest._retry = true;
        try {
            const refreshResponse = await axios.post('/api/auth/refresh-token');
            const newToken = refreshResponse.data.Token;
            
            // Update cookie or localStorage
            document.cookie = `JwtToken=${newToken}; expires=${new Date(Date.now() + 3600000).toUTCString()}; path=/; secure; samesite=strict`;
            // localStorage.setItem('JwtToken', newToken);
            
            // Retry the original request with the new token
            originalRequest.headers.Authorization = `Bearer ${newToken}`;
            return axios(originalRequest);
        } catch (refreshError) {
            // Refresh failed — send user to login
            window.location.href = '/Account/Login';
            return Promise.reject(refreshError);
        }
    }
    return Promise.reject(error);
});
5. Critical Security Notes
  • XSS Protection: If using non-HttpOnly cookies or localStorage, make sure your Vue app is protected against XSS attacks (sanitize user input, use Vue's built-in escaping).
  • CSRF Protection: If letting the API accept cookies, enable CSRF protection for your API endpoints (ASP.NET Core has built-in middleware for this).
  • HTTPS: Always use HTTPS in production to prevent token interception.
  • Token Lifespan: Keep JWT expiration short (1-2 hours) and rely on the refresh endpoint instead of long-lived tokens.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 07:05:38