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

Angular14与.NET7页面刷新时Http解析失败问题求助

Angular 14 + .NET 7 刷新页面Http解析失败问题解决

问题现象

刷新页面时触发以下错误:

Http failure during parsing for https://localhost:6001/Account/Login?ReturnUrl=%2Fapi%2Faccount%2Fcurrentuser

错误截图:
Http解析失败错误截图

问题定位

移除下方代码并删除GetCurrentUser中角色相关逻辑后,应用恢复正常但丢失角色功能,说明问题出在Identity服务配置和角色处理逻辑上:

builder.Services.AddIdentity<ApplicationUser, ApplicationRole>()
                 .AddRoles<ApplicationRole>()
                 .AddEntityFrameworkStores<ShopDbContext>();

核心原因

  1. Identity服务重复注册:代码先调用AddIdentityCore<ApplicationUser>(),又重复调用AddIdentity<ApplicationUser, ApplicationRole>(),导致服务冲突,触发默认Cookie认证流程而非JWT认证,后端返回登录页面HTML而非预期JSON,前端解析失败。
  2. 角色关联配置缺失:自定义ApplicationRole与ApplicationUser的关联实体(ApplicationUserRole)未在DbContext中正确配置,角色操作时触发异常。

解决方案

步骤1:修复Identity服务注册逻辑

修改AddIdentityServices方法,避免重复注册,统一用AddIdentityCore扩展角色支持:

public static IServiceCollection AddIdentityServices(this IServiceCollection services, IConfiguration config)
{
    // 初始注册IdentityCore并指定用户类型
    var builder = services.AddIdentityCore<ApplicationUser>(options =>
    {
        // 可按需添加密码复杂度、账号锁定等配置
    });

    // 传入角色类型构建IdentityBuilder
    builder = new IdentityBuilder(builder.UserType, typeof(ApplicationRole), builder.Services);
    // 添加SignInManager、角色管理器及EF存储支持
    builder.AddSignInManager<SignInManager<ApplicationUser>>()
           .AddRoles<ApplicationRole>()
           .AddRoleManager<RoleManager<ApplicationRole>>()
           .AddEntityFrameworkStores<ShopDbContext>();

    // 配置JWT认证
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["Token:Key"])),
                    ValidIssuer = config["Token:Issuer"],
                    ValidateIssuer = true,
                    ValidateAudience = false
                };
            });

    return services;
}

步骤2:配置DbContext角色关联

确保ShopDbContext继承带自定义角色的IdentityDbContext,并配置用户角色关联表:

public class ShopDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, int, 
    IdentityUserClaim<int>, ApplicationUserRole, IdentityUserLogin<int>,
    IdentityRoleClaim<int>, IdentityUserToken<int>>
{
    public ShopDbContext(DbContextOptions<ShopDbContext> options) : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        // 配置用户角色关联表映射
        modelBuilder.Entity<ApplicationUserRole>(userRole =>
        {
            userRole.HasKey(ur => new { ur.UserId, ur.RoleId });

            userRole.HasOne(ur => ur.Role)
                .WithMany(r => r.UserRoles)
                .HasForeignKey(ur => ur.RoleId)
                .IsRequired();

            userRole.HasOne(ur => ur.User)
                .WithMany(u => u.UserRoles)
                .HasForeignKey(ur => ur.UserId)
                .IsRequired();
        });
    }
}

同时给ApplicationUser添加角色集合属性:

public class ApplicationUser : IdentityUser<int>
{
    // 原有属性...
    public virtual ICollection<ApplicationUserRole> UserRoles { get; set; }
}

步骤3:完善GetCurrentUser方法逻辑

添加角色后保存上下文,同时规范异常返回:

[Authorize]
[HttpGet]
public async Task<ActionResult<UserDto>> GetCurrentUser()
{
    var user = await _userManager.FindByEmailFromClaimsPrincipal(User);
    if (user == null)
    {
        return NotFound(); // 用NotFound替代null,符合REST规范
    }

    var role = (await _userManager.GetRolesAsync(user)).FirstOrDefault();
    if (role == null)
    {
        role = Role.Standard.ToString("f");
        var result = await _userManager.AddToRoleAsync(user, role);
        if (result.Succeeded)
        {
            await _context.SaveChangesAsync(); // 保存角色添加操作
        }
        else
        {
            return BadRequest(result.Errors); // 返回角色添加失败的错误信息
        }
    }

    return new UserDto
    {
        Email = user.Email,
        Token = _tokenService.CreateToken(user),
        DisplayName = user.DisplayName,
        Role = role,
    };
}

步骤4:前端请求添加格式声明

在请求头中明确指定接受JSON格式,避免解析异常:

loadCurrentUser(token: string | null): Observable<void> {
    if (token === null) {
        this.currentUserSource.next(null);
        return of();
    }
    let headers = new HttpHeaders()
        .set('Authorization', `Bearer ${token}`)
        .set('Accept', 'application/json'); // 添加Accept头指定JSON格式
    return this.http.get(this.baseUrl + 'account', { headers }).pipe(
        map((user: any) => {
            console.log("user = ", user);
            if (user) {
                localStorage.setItem('token', user.token);
                this.currentUserSource.next(user);
            }
        }),
        catchError(error => {
            console.error('请求错误:', error);
            return throwError(() => error);
        })
    );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 18:01:18