[英]How to get user information after sending JWT to a new controller
I'm working on an ASP.Net Core API project. 我正在研究ASP.Net Core API项目。
There are 2 controllers, controller A and B, I use Postman to pass my username and password to controller A action method, and it successfully returns a JWT. 有两个控制器,控制器A和B,我使用Postman将用户名和密码传递给控制器A的操作方法,它成功返回了JWT。 After I pass the JWT to controller B, I hope to get the username and role information of the credential which I had input into the controller A. 将JWT传递给控制器B后,希望获得输入到控制器A中的凭证的用户名和角色信息。
The code in controller B below shows the way I get the user info. 下面控制器B中的代码显示了我获取用户信息的方式。
public async Task<ActionResult> Get()
{
var user = await _userManager.GetUserAsync(HttpContext.User);
var role = await _userManager.GetRolesAsync(user);
return Ok(user);
}
But after I sent the JWT, I got null user. 但是在发送JWT之后,我得到了空用户。
Edit1: EDIT1:
ConfigureServices method in my Startup.cs: 我的Startup.cs中的ConfigureServices方法:
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: 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>();
});
}
}
Controller Action for JWT generation (Controller A in the previous context): 用于生成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();
}
Controller method for getting user info (Controller B in the previous context): 获取用户信息的控制器方法(在先前的上下文中为控制器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);
}
}
Edit 2: Startup.cs Configure 编辑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();
}
The reason is that you're using UserManager<JWT_AuthUser>.GetUserAsync(user)
to get the principal, which belongs to the Identity
Authentication Scheme. 原因是您正在使用UserManager<JWT_AuthUser>.GetUserAsync(user)
来获取主体,该主体属于Identity
验证方案。 As the document describes, this method will only read the IdentityOptions.ClaimsIdentity.UserIdClaimType claim: 如文档所述,此方法将仅读取IdentityOptions.ClaimsIdentity.UserIdClaimType声明:
Returns the user corresponding to the IdentityOptions.ClaimsIdentity.UserIdClaimType claim in the principal or null. 返回与主体中的IdentityOptions.ClaimsIdentity.UserIdClaimType声明对应的用户,或者为null。
Note the claims
issued by your GetToken()
method is an empty list : 请注意,您的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
);
....
}
Since there's no such a IdentityOptions.ClaimsIdentity.UserIdClaimType
claim , you'll get a null
when invoking var user = await _userManager.GetUserAsync(HttpContext.User);
由于没有这样的IdentityOptions.ClaimsIdentity.UserIdClaimType
声明 ,因此在调用var user = await _userManager.GetUserAsync(HttpContext.User);
时,您将获得null
var user = await _userManager.GetUserAsync(HttpContext.User);
. 。
And because the user is null
, it throws when invoking await _userManager.GetRolesAsync(user);
并且由于user为null
,因此在调用await _userManager.GetRolesAsync(user);
时抛出该异常await _userManager.GetRolesAsync(user);
IdentityOptions
to get the UserIdClaimType
: 注入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();
}
//add claims var claims = new List<Claim>(); claims.Add(new Claim(this._idOpts.ClaimsIdentity.UserIdClaimType, user.Id )); //create token var token = new JwtSecurityToken( issuer: "issuer", audience: "audience", expires: DateTime.Now.AddHours(1), claims: claims, signingCredentials: signingCredentials );
Another question inspired me enter link description here by the idea of holding user info inside JWT claim. 另一个问题激发了我在JWT声明中保留用户信息的想法,从而在此处输入链接描述 。
In the JWT generating action method inside Controller A, I use Usermanager to get user information of my credentials and put them into JWT claims. 在控制器A内的JWT生成操作方法中,我使用Usermanager来获取我的凭据的用户信息并将其放入JWT声明中。
var roles = await _userManager.GetRolesAsync(user);
var claims = new List<Claim>();
claims.Add( new Claim("Role", roles[0]));
After passing the JWT to controller B, this piece of code help me get the claim info: 将JWT传递给控制器B后,这段代码可帮助我获取索赔信息:
var roleClaim = User.Claims.FirstOrDefault(x => x.Type.Equals("Role", StringComparison.InvariantCultureIgnoreCase));
Which fetch me the role 哪个让我扮演角色
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.