C# .NET核心MVC和Web API两种身份验证方案

C# .NET核心MVC和Web API两种身份验证方案,c#,asp.net-mvc,authentication,.net-core,jwt,C#,Asp.net Mvc,Authentication,.net Core,Jwt,我有一个MVC应用程序和一个公开的API端点。我使用Identity Core的默认值验证了我的MVC应用程序,我使用User.FindFirstValue(ClaimTypes.NameIdentifier)查找某个用户是否登录,等等 对于我的API端点,我使用JWT身份验证,以下是JWT的配置代码: services.AddAuthentication(options => { options.DefaultAuthenticateScheme

我有一个MVC应用程序和一个公开的API端点。我使用Identity Core的默认值验证了我的MVC应用程序,我使用
User.FindFirstValue(ClaimTypes.NameIdentifier)
查找某个用户是否登录,等等

对于我的API端点,我使用JWT身份验证,以下是JWT的配置代码:

services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(jwt =>
        {
            var key = Encoding.ASCII.GetBytes(Configuration["Jwt:Secret"]);

        jwt.SaveToken = true;
        jwt.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(key),
            ValidateIssuer = false,
            ValidateAudience = false,
            RequireExpirationTime = false,
            ValidateLifetime = true
        };
    });
以下是令牌请求的控制器:

[HttpPost]
[Route("token")]
public async Task<IActionResult> Token([FromBody] UserLoginRequest user)
{
    if (ModelState.IsValid)
    {
        var existingUser = await _userManager.FindByEmailAsync(user.Email);
        if (existingUser == null)
        {
            return BadRequest();
        }

         var isCorrect = await _userManager.CheckPasswordAsync(existingUser, user.Password);
         if (isCorrect)
         {
             var jwtToken = _identityService.GenerateJwtToken(existingUser);

             return Ok(new RegistrationResponse()
                {
                    Result = true,
                    Token = jwtToken
                });
         }
         else
         {
             return BadRequest();
         }

    }

    return BadRequest();
}

但很明显,这个解决方案无法正常工作,因为一旦我启动我的MVC应用程序并尝试登录,我就会被重定向回索引,而我仍然是未经授权的。反之亦然,在API中,当我进行邮递员调用时,我得到令牌,当我尝试调用我的书签控制器来查询用户的书签时,我得到零,尽管该用户有书签


任何关于如何实现这一点的想法都将受到欢迎。

在我的JWT令牌生成器中,我获得了我希望存储为声明的用户的详细信息,如用户名,可用于识别用户

public static class JwtTokenExtensions
{
    /// <summary>
    /// Generates a JWT Bearer token containing the users email
    /// </summary>
    /// <param name="user"></param>
    /// <returns></returns>
    public static string GenerateJwtToken(this Identity user)
    {
        // Set our token claims
        Claim[] claims = {
            // Unique ID for this token
            new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")),

            new(JwtRegisteredClaimNames.Email, user.Email),
            // The username using the Identity name so it fills out the HttpContext.User.Identity.Name value
            new(ClaimsIdentity.DefaultNameClaimType, user.UserName),
            // Add user Id so that UserManager.GetUserAsync can find the user based on Id
            new Claim(ClaimTypes.NameIdentifier, user.Id)
        };

        // Create the credentials used to generate the token
        SigningCredentials credentials = 
        new SigningCredentials(SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:SecretKey"])),
            SecurityAlgorithms.HmacSha256);

        // Generate the Jwt Token that lasts for an hour before expiring
        JwtSecurityToken token =
            new JwtSecurityToken
            (Configuration["Jwt:Issuer"],
            Configuration["Jwt:Audience"], 
            claims:claims,
            signingCredentials:credentials,
            expires: DateTime.Now.AddHours(1));

        // Return the generated token.
        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}
公共静态类JwtTokenExtensions
{
/// 
///生成包含用户电子邮件的JWT承载令牌
/// 
/// 
/// 
公共静态字符串GenerateJwtToken(此标识用户)
{
//设定我们的代币索赔
索赔[]索赔={
//此令牌的唯一ID
新建(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString(“N”)),
新的(JwtRegisteredClaimNames.Email,user.Email),
//使用标识名的用户名,以填充HttpContext.User.Identity.name值
新建(ClaimsIdentity.DefaultNameClaimType,user.UserName),
//添加用户Id,以便UserManager.GetUserAsync可以基于Id找到用户
新声明(ClaimTypes.NameIdentifier,user.Id)
};
//创建用于生成令牌的凭据
签名凭据凭据=
新的签名凭据(SymmetricSecurityKey(Encoding.UTF8.GetBytes(配置[“Jwt:SecretKey]”)),
安全算法(HmacSha256);
//生成在到期前持续一小时的Jwt令牌
JwtSecurityToken令牌=
新JwtSecurityToken
(配置[“Jwt:Issuer”],
配置[“Jwt:观众”],
索赔:索赔,
签署证书:证书,
expires:DateTime.Now.AddHours(1));
//返回生成的令牌。
返回新的JwtSecurityTokenHandler().WriteToken(令牌);
}
}
在具有JWT授权的api控制器中,我可以通过HttpContext获得用户
var user=await\u userManager.GetUserAsync(HttpContext.user)

在我的JWT令牌生成器中,我得到了我想存储为声明的用户的详细信息,例如用户名,它可以用来识别用户

public static class JwtTokenExtensions
{
    /// <summary>
    /// Generates a JWT Bearer token containing the users email
    /// </summary>
    /// <param name="user"></param>
    /// <returns></returns>
    public static string GenerateJwtToken(this Identity user)
    {
        // Set our token claims
        Claim[] claims = {
            // Unique ID for this token
            new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")),

            new(JwtRegisteredClaimNames.Email, user.Email),
            // The username using the Identity name so it fills out the HttpContext.User.Identity.Name value
            new(ClaimsIdentity.DefaultNameClaimType, user.UserName),
            // Add user Id so that UserManager.GetUserAsync can find the user based on Id
            new Claim(ClaimTypes.NameIdentifier, user.Id)
        };

        // Create the credentials used to generate the token
        SigningCredentials credentials = 
        new SigningCredentials(SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:SecretKey"])),
            SecurityAlgorithms.HmacSha256);

        // Generate the Jwt Token that lasts for an hour before expiring
        JwtSecurityToken token =
            new JwtSecurityToken
            (Configuration["Jwt:Issuer"],
            Configuration["Jwt:Audience"], 
            claims:claims,
            signingCredentials:credentials,
            expires: DateTime.Now.AddHours(1));

        // Return the generated token.
        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}
公共静态类JwtTokenExtensions
{
/// 
///生成包含用户电子邮件的JWT承载令牌
/// 
/// 
/// 
公共静态字符串GenerateJwtToken(此标识用户)
{
//设定我们的代币索赔
索赔[]索赔={
//此令牌的唯一ID
新建(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString(“N”)),
新的(JwtRegisteredClaimNames.Email,user.Email),
//使用标识名的用户名,以填充HttpContext.User.Identity.name值
新建(ClaimsIdentity.DefaultNameClaimType,user.UserName),
//添加用户Id,以便UserManager.GetUserAsync可以基于Id找到用户
新声明(ClaimTypes.NameIdentifier,user.Id)
};
//创建用于生成令牌的凭据
签名凭据凭据=
新的签名凭据(SymmetricSecurityKey(Encoding.UTF8.GetBytes(配置[“Jwt:SecretKey]”)),
安全算法(HmacSha256);
//生成在到期前持续一小时的Jwt令牌
JwtSecurityToken令牌=
新JwtSecurityToken
(配置[“Jwt:Issuer”],
配置[“Jwt:观众”],
索赔:索赔,
签署证书:证书,
expires:DateTime.Now.AddHours(1));
//返回生成的令牌。
返回新的JwtSecurityTokenHandler().WriteToken(令牌);
}
}
在具有JWT授权的api控制器中,我可以通过HttpContext获得用户
var user=await\u userManager.GetUserAsync(HttpContext.user)

在控制器中为您的令牌请求添加[AllowAnonymous],如下所示:

[AllowAnonymous]
[HttpPost]
[Route("token")]
public async Task<IActionResult> Token([FromBody] UserLoginRequest user)
{
    // snip...
}
[AllowAnonymous]
[HttpPost]
[路由(“令牌”)]
公共异步任务令牌([FromBody]UserLoginRequest用户)
{
//剪断。。。
}

在令牌请求的控制器中,尝试添加[AllowAnonymous],如下所示:

[AllowAnonymous]
[HttpPost]
[Route("token")]
public async Task<IActionResult> Token([FromBody] UserLoginRequest user)
{
    // snip...
}
[AllowAnonymous]
[HttpPost]
[路由(“令牌”)]
公共异步任务令牌([FromBody]UserLoginRequest用户)
{
//剪断。。。
}

在请求书签时,您是否随请求一起发送承载令牌?其次,您的mvc身份验证失败,因为您已将JWT身份验证指定为defualtauthentication方案。My bookmarks实体有一个UserId属性,我使用该属性从该特定用户检索所有书签。在MVC中,我可以轻松地使用(User.FindFirstValue(ClaimTypes.nameignifier))检索userId,但在我的API调用中,我得到的书签为零@Jeffery@Jeffery还有,我该怎么做才能使会话身份验证和JWT身份验证都成为默认设置对于我所做的所有JWT身份验证,我已经编写了自己的JWT令牌生成器,其中我指定了声明类型,如NameIdentifier和其他我可能特别需要的声明。我发布了我的代码作为答案,并提供了一些帮助。请查看它是否解决了您向书签发出请求的问题,您是否随请求一起发送承载令牌?第二,你的mvc aut