如何使用 JWT 令牌在 .NET Core API 中检索当前用户数据?
Posted
技术标签:
【中文标题】如何使用 JWT 令牌在 .NET Core API 中检索当前用户数据?【英文标题】:How use a JWT token to retrieve current user data in .NET Core API? 【发布时间】:2021-07-22 10:02:57 【问题描述】:我已经实现了 JWT 令牌,以了解当前用户在 MVC 控制器正在使用的 API 应用程序中的身份。 我正在构建类似论坛应用程序的东西。用户必须登录才能发帖,所以我基本上是在尝试使用 JWT 令牌来存储当前用户的电子邮件。 当用户单击“创建帖子”时,操作应该获取令牌及其值,问题是我不知道如何使用令牌来保护控制器或从当前用户检索数据,我已经复制并粘贴了jwt.io中的token,检查数据是否正确存储在token中,值(用户的email)是否正确存储。
具有“登录”操作的 API 控制器:
public async Task<IActionResult> login([FromBody] Usuario model)
//check if user exists and the password is correct
//generates the token
var SecretKey = config.GetValue<string>("SecretKey");
var key = Encoding.ASCII.GetBytes(SecretKey);
var claims = new ClaimsIdentity(new Claim[]
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Mail)
);
claims.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Mail));
var tokenDesc = new SecurityTokenDescriptor
Subject = claims,
Expires = DateTime.UtcNow.AddMinutes(20),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
;
var tokenHandler = new JwtSecurityTokenHandler();
var createdToken = tokenHandler.CreateToken(tokenDesc);
string bearer_token = tokenHandler.WriteToken(createdToken);
using(var client = new HttpClient())
client.DefaultRequestHeaders.Add("Authorization", "Bearer" + bearer_token);
return Ok(bearer_token);
使用 API 的 MVC 控制器:
public async Task<IActionResult> login(Usuario model)
HttpClient hc = new HttpClient();
hc.BaseAddress = new Uri("https://localhost:44325/api/Usuarios/");
var login = await hc.PostAsJsonAsync<Usuario>("login", model);
//check the response
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
identity.AddClaim(new Claim(ClaimTypes.Name, model.Email));
var principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
HttpContext.Session.SetString("JWToken", login.ToString());
hc.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", login.ToString());
return RedirectToAction("IndexForumList", "ForumControllerMVC");
这是“创建帖子”的 API 方法以及应使用令牌的位置,这里 userId
为空:
public async Task<IActionResult> createPost([FromForm]ForumModel model)
string userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
//retrieves the current user email, validates and save the content to database
这是“创建帖子”的 MVC 方法:
public async Task<IActionResult> createPost(ForumModel model)
HttpClient hc = new HttpClient();
hc.BaseAddress = new Uri("https://localhost:44325/api/Usuarios/");
//var userPost = hc.PostAsJsonAsync<ForumModel>("Usuarios/createPost", model);
var userPost = await hc.PostAsync("createPost", formContent);
if(userPost.IsSuccessStatusCode == true)
return RedirectToAction("IndexForumList", "ForoControllerMVC");
由于我对 JWT 缺乏了解,我一直受此困扰,感谢任何帮助。
更新
startup.cs
public void ConfigureServices(IServiceCollection services)
var key = Encoding.ASCII.GetBytes(Configuration.GetValue<string>("SecretKey"));
services.AddAuthentication(x =>
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
).AddJwtBearer(x =>
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
;
);
services.AddSession(
options =>
options.IdleTimeout = TimeSpan.FromMinutes(10);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
);
【问题讨论】:
当您从 mvc 调用时,您需要添加令牌作为标头。然后你需要在 api 控制器或操作中添加授权属性。我相信你已经在配置服务中设置了所有内容。 您已经添加了两次ClaimTypes.NameIdentifier
。 UserManager
将寻找声明 IdentityOptions.ClaimsIdentity.UserIdClaimType
/ .UserNameClaimType
以获取数据库用户。您可以在启动时更改声明类型名称。您的“API 应用程序”和“MVC 控制器”是同一个程序还是分开的?
@Selik 好吧,我认为服务的部分配置正确,我已经更新了问题的那部分。现在我想我还有一个问题,如何将令牌添加为标头?
@JeremyLakeman 所以,我只需要留下一个带有电子邮件值的ClaimTypes.NameIdentifier
,或者类似的东西?是的,API 与 MVC 在同一个项目中。
在您的 createpost MVC 方法中,您必须为 httpclient 调用添加授权标头,并将授权属性添加到 api 操作/控制器。 httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer" + "your_token");
【参考方案1】:
如果我正确理解您的问题, 为了保护您的 API,您可以使用 [Authorize] 属性对其进行装饰。例如 -
[Authorize]
[HttpGet]
public IActionResult GetAll()
var users = _userService.GetAll();
return Ok(users);
并且要验证您的令牌,因为您使用 .netcore 作为您的 api,您必须创建一个中间件,该中间件将在您的请求到达 API 端点之前验证令牌。您可以关注this 教程,了解如何将 JWT 与 ASP.NET 核心一起使用。
要在您的情况下获取用户 ID,您必须先验证令牌,然后提取用户 ID。尝试将 createPost api 中的代码更改为此 -
public async Task<IActionResult> createPost([FromForm]ForumModel model)
var tokenHandler = new JwtSecurityTokenHandler();
var SecretKey = config.GetValue<string>("SecretKey");
var key = Encoding.ASCII.GetBytes(SecretKey);
var token = HttpContext.Request.Headers["Authorization"];
tokenHandler.ValidateToken(token, new TokenValidationParameters
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
ClockSkew = TimeSpan.Zero
, out SecurityToken validatedToken);
var jwtToken = (JwtSecurityToken)validatedToken;
var userId = int.Parse(jwtToken.Claims.First(x => x.Type == "NameIdentifier").Value);
虽然这应该在中间件中处理,然后您可以将经过身份验证的用户附加到当前的 HttpContext.Items 集合,以使其在当前请求的范围内可访问。所有这些都在教程中详细解释。希望对您有所帮助!
【讨论】:
感谢您的帮助,我一直在阅读这篇文章,现在就tokenHandler.ValidateToken(token, new TokenValidationParameters...
而言,token
参数指的是什么,或者它是在哪里创建的以便在那里使用?
哦,我明白了。我错过了在代码中添加令牌参数。它基本上是您在登录 api 中创建的 jwt 令牌。当您调用您的 api 并附加授权标头时,您应该能够通过 - var token = HttpContext.Request.Headers["Authorization"]; 访问它我也更新了代码。很抱歉错过了。以上是关于如何使用 JWT 令牌在 .NET Core API 中检索当前用户数据?的主要内容,如果未能解决你的问题,请参考以下文章