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

Vue.js与ASP.NET Core应用LTI认证后JWT存储及鉴权问题

问题分析与解决方案

问题概述

基于Vue.js客户端+ASP.NET Core 9后端搭建的系统,需通过LTI认证被第三方平台调用,对方仅首次请求时发送鉴权JWT令牌。当前配置存在以下问题:

  • 在第三方平台https://saltire.lti.app/platform的iframe中加载客户端,无法读取后端设置的JWT Cookie;
  • 新标签页加载时同样看不到Cookie,/vue/api/me接口鉴权失败;
  • 浏览器控制台提示“Cookie “jwt” has been rejected for invalid domain”,手动指定公网或localhost域名均无效。

后端当前通过OnMessageReceived事件从表单提取JWT并设置HttpOnly Cookie,LTI流程为第三方POST到/launch接口,验证通过后通过RedirectPreserveMethod("/")重定向到客户端。本地用ngrok暴露公网地址https://15e1-93-41-196-8.ngrok-free.app,后端运行在https://localhost:7093,Vue应用在https://localhost:64928。


可行解决方案

方案1:修复Cookie域名配置

Cookie被拒绝的核心原因是域名不匹配,浏览器不允许跨域名设置Cookie。需动态适配请求域名,或开发环境不指定域名让浏览器自动匹配。

修改OnMessageReceived中的Cookie设置代码:

context.Response.Cookies.Append("jwt", token, new CookieOptions
{
    HttpOnly = true,
    Secure = true,
    SameSite = SameSiteMode.None,
    // 开发环境不指定域名,生产环境自动匹配当前请求域名
    Domain = Environment.IsDevelopment() ? null : new Uri(context.Request.Host.Value).Host
});

额外注意:

  • 后端与Vue应用需部署在同一域名/子域名下,否则Cookie无法跨域共享;
  • ngrok测试时,所有请求需通过ngrok公网地址访问,避免localhost与ngrok域名混用。

方案2:前端存储JWT并在请求头携带

放弃Cookie方案,将JWT返回给前端存储,每次请求接口时通过请求头传递令牌。

  1. 修改/launch接口,返回内嵌脚本将JWT存入前端存储:
[HttpPost("launch")]
[Authorize]
[Consumes("application/x-www-form-urlencoded")]
public async Task<IActionResult> PostLaunch([FromForm] JwtPayload request, HttpContext context)
{
    await Task.CompletedTask;

    if (HttpContext.User.Identity?.IsAuthenticated == true)
    {
        var token = context.Request.Form[jwtSection.TokenField];
        // 返回跳转页面,将token存入localStorage后跳转到客户端
        return Content($@"
            <script>
                localStorage.setItem('lti_jwt', '{token}');
                window.location.href = '/';
            </script>
        ", "text/html");
    }
    return Unauthorized();
}
  1. 在Vue应用中添加请求拦截器,自动携带令牌:
// 以axios为例
axios.interceptors.request.use(config => {
    const token = localStorage.getItem('lti_jwt');
    if (token) {
        config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
});

后端JWTBearer默认支持从请求头读取令牌,无需额外修改配置。

方案3:使用ASP.NET Core Session管理身份

利用Session替代手动Cookie管理,由框架自动维护会话凭证。

  1. 配置Session服务:
// Program.cs中添加
builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromHours(1);
    options.Cookie.HttpOnly = true;
    options.Cookie.Secure = CookieSecurePolicy.Always;
    options.Cookie.SameSite = SameSiteMode.None;
});
  1. 启用Session中间件(需放在UseAuthorization之前):
app.UseSession();
  1. 修改/launch接口存储用户信息到Session:
[HttpPost("launch")]
[Authorize]
[Consumes("application/x-www-form-urlencoded")]
public async Task<IActionResult> PostLaunch([FromForm] JwtPayload request)
{
    await Task.CompletedTask;

    if (HttpContext.User.Identity?.IsAuthenticated == true)
    {
        var userName = HttpContext.User.Claims.FirstOrDefault(f => f.Type == "name")?.Value ?? "";
        HttpContext.Session.SetString("UserName", userName);
        return RedirectPreserveMethod("/");
    }
    return Unauthorized();
}
  1. 修改/vue/api/me接口从Session读取信息:
app.MapGet("vue/api/me", (HttpContext context) =>
{
    var userName = context.Session.GetString("UserName");
    return new { name = userName };
}).RequireAuthorization();

关键注意事项

  • iframe/跨域场景下,SameSite=None必须配合Secure=true,且浏览器需支持该配置;
  • 若前后端跨域,需配置CORS允许携带凭证(添加.WithCredentials());
  • ngrok测试时,确保所有请求统一使用ngrok公网地址,避免域名不一致导致的Cookie问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 00:33:20