【问题标题】:How to get user information after sending JWT to a new controller将 JWT 发送到新控制器后如何获取用户信息
【发布时间】:2020-01-19 04:21:26
【问题描述】:

我正在开发一个 ASP.Net Core API 项目。

有2个控制器,控制器A和B,我使用Postman将我的用户名和密码传递给控制器​​A的action方法,它成功返回了一个JWT。 在我将 JWT 传递给控制器​​ B 后,我希望得到我输入到控制器 A 中的凭证的用户名和角色信息。

下面控制器 B 中的代码显示了我获取用户信息的方式。

public async Task<ActionResult> Get()
        {
            var user = await _userManager.GetUserAsync(HttpContext.User);
            var role = await _userManager.GetRolesAsync(user);
            return Ok(user);
        }

但是在我发送 JWT 之后,我得到了 null 用户。

编辑1:

我的 Startup.cs 中的 ConfigurationServices 方法:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = true,
                        ValidateAudience = true,
                        ValidateIssuerSigningKey = true,
                        ValidIssuer = "issuer",
                        ValidAudience = "audience",
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("This is my super long security Key 123"))
                    };
                });

            services.AddDbContext<JWT_AuthContext>(option => option.UseSqlServer(Configuration.GetConnectionString("JWT_AuthContextConnection")));

        }

IdentityHostingStartup.cs:

public class IdentityHostingStartup : IHostingStartup
    {
        public void Configure(IWebHostBuilder builder)
        {
            builder.ConfigureServices((context, services) => {
                services.AddDbContext<JWT_AuthContext>(options =>
                    options.UseSqlServer(
                        context.Configuration.GetConnectionString("JWT_AuthContextConnection")));

                services.AddDefaultIdentity<JWT_AuthUser>()
                    .AddRoles<JWT_AuthRole>()
                    .AddEntityFrameworkStores<JWT_AuthContext>();
            });
        }
    }

用于 JWT 生成的控制器动作(前文中的控制器 A):

[Route("api/[controller]")]
    [ApiController]
    public class AuthController : ControllerBase
    {
        private UserManager<JWT_AuthUser> _userManager;
        public AuthController(UserManager<JWT_AuthUser> userManager)
        {
            _userManager = userManager;
        }

        [HttpPost("token")]
        public async Task<ActionResult> GetToken()
        {
            var header = Request.Headers["Authorization"];
            if(header.ToString().StartsWith("Basic"))
            {
                var loginInfo = header.ToString().Substring("Basic ".Length).Trim();
                var userNameAndPassword = Encoding.UTF8.GetString(Convert.FromBase64String(loginInfo)); //username:password
                var userName = userNameAndPassword.Split(":")[0];
                var password = userNameAndPassword.Split(":")[1];
                var user = await _userManager.FindByNameAsync(userName);

                if (user != null && await _userManager.CheckPasswordAsync(user,password))
                {
                    //security key
                    string securityKey = "This is my super long security Key 123";

                    //symmetric security key
                    var symmetricSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(securityKey));

                    //signing credentials
                    var signingCredentials = new SigningCredentials(symmetricSecurityKey, SecurityAlgorithms.HmacSha256Signature);

                    //add claims
                    var claims = new List<Claim>();

                    //create token
                    var token = new JwtSecurityToken(
                        issuer: "issuer",
                        audience: "audience",
                        expires: DateTime.Now.AddHours(1),
                        claims: claims,
                        signingCredentials: signingCredentials
                        );

                    //return token
                    return Ok(new JwtSecurityTokenHandler().WriteToken(token));
                }

            }

            return Unauthorized();
}

获取用户信息的控制器方法(前文中的控制器B):

[Authorize]
    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase
    {

        private UserManager<JWT_AuthUser> _userManager;
        public ValuesController(UserManager<JWT_AuthUser> userManager)
        {
            _userManager = userManager;
        }

        // GET api/values
        [HttpGet]
        public async Task<ActionResult> Get()
        {
            var user = await _userManager.GetUserAsync(HttpContext.User);
            var role = await _userManager.GetRolesAsync(user);
            return Ok(user);
        }
}

编辑 2: Startup.cs 配置

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseAuthentication();
            app.UseMvc();
        }

【问题讨论】:

  • 1.请出示您的Startup.cs。 2. 还请包括您将 JWT 传递给控制器​​ B 的请求
  • 能否分享您的_userManager.GetRolesAsync(user); 方法代码,并在调用之前检查user != null
  • @awais,对不起,我没有得到“分享你的 _userManager.GetRolesAsync(user)”,我直接使用这段代码。
  • @itminus,是的,我已经提供了我项目的额外代码,我将 JWT 传递给控制器​​ B 的方式是将 JWT 复制到 Postman-Authorization-Bearer Token。

标签: c# asp.net asp.net-core asp.net-web-api jwt


【解决方案1】:

原因是您使用UserManager&lt;JWT_AuthUser&gt;.GetUserAsync(user) 获取主体,它属于Identity 身份验证方案。如文档所述,此方法将仅读取 IdentityOptions.ClaimsIdentity.UserIdClaimType 声明:

返回与主体中的 IdentityOptions.ClaimsIdentity.UserIdClaimType 声明对应的用户或 null。

注意您的GetToken() 方法发出的claims一个空列表

[HttpPost("token")]
public async Task<ActionResult> GetToken()
{
    ....
        //add claims
        var claims = new List<Claim>();

        //create token
        var token = new JwtSecurityToken(
            issuer: "issuer",
            audience: "audience",
            expires: DateTime.Now.AddHours(1),
            claims: claims,
            signingCredentials: signingCredentials
            );
   ....

}

由于没有这样的IdentityOptions.ClaimsIdentity.UserIdClaimType 声明,因此在调用var user = await _userManager.GetUserAsync(HttpContext.User); 时,您将得到一个null

因为用户是null,所以在调用await _userManager.GetRolesAsync(user);时会抛出

如何修复

  1. 注入IdentityOptions得到UserIdClaimType
    [Route("api/[controller]")]
    [ApiController]
    public class AuthController : ControllerBase
    {
        private UserManager<IdentityUser> _userManager;
        private readonly IdentityOptions _idOpts;

        public AuthController(UserManager<IdentityUser> userManager,IOptions<IdentityOptions> optionsAccessor)
        {
            _userManager = userManager;
            this._idOpts = optionsAccessor.Value?? new IdentityOptions();
        }

  1. 在发送令牌之前添加声明:
//添加声明 var claim = new List(); claims.Add(new Claim(this._idOpts.ClaimsIdentity.UserIdClaimType, user.Id )); //创建令牌 var token = new JwtSecurityToken( 发行人:“发行人”, 观众:“观众”, 过期:DateTime.Now.AddHours(1), 索赔:索赔, 签名凭据:签名凭据 );

【讨论】:

    【解决方案2】:

    另一个问题启发了我enter link description here 在 JWT 声明中保存用户信息的想法。

    在控制器 A 内的 JWT 生成操作方法中,我使用 Usermanager 获取我的凭据的用户信息并将它们放入 JWT 声明中。

    var roles = await _userManager.GetRolesAsync(user);
    var claims = new List<Claim>();
    claims.Add( new Claim("Role", roles[0]));
    

    将 JWT 传递给控制器​​ B 后,这段代码帮助我获取声明信息:

    var roleClaim = User.Claims.FirstOrDefault(x => x.Type.Equals("Role", StringComparison.InvariantCultureIgnoreCase));
    

    这让我得到了这个角色

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-28
    • 1970-01-01
    • 1970-01-01
    • 2017-01-11
    • 1970-01-01
    相关资源
    最近更新 更多