令牌无法存储在 .NET Core 中
Posted
技术标签:
【中文标题】令牌无法存储在 .NET Core 中【英文标题】:Token can't store in .NET Core 【发布时间】:2020-07-12 04:02:29 【问题描述】:我有一个使用 .NET 核心 3.1 版的项目,我正在使用令牌进行登录。使用 Postman 进行测试时一切正常,它创建了令牌,我可以使用它来访问主页。
问题是,当我开始在客户端进行测试时,它不起作用。我登录后调试看到,生成了token,但是因为[Authorize]
属性,我无法访问HomeController
。
这是我生成令牌的代码:
public async Task<HttpResponse<LoginResult>> GetTokenAsync(LoginRequest loginInfo)
var audience = await _audiences.FindAsync(a => a.Id == loginInfo.ClientId);
string message = string.Empty;
if (audience != null)
bool audienceIsValid = _jwtProvider.ValidateAudience(audience.Issuer
, audience.SecretKey
, ref message);
if (audienceIsValid)
return await GenerateToken(loginInfo);
else
message = ErrorMessages.Login_AudienceInvalid;
else
message = string.Format(ErrorMessages.Login_Not_Permitted, "Your client Id");
return HttpResponse<LoginResult>.Error(message, HttpStatusCode.BadRequest);
我猜该令牌无法正确存储。
我错过了什么?
更新 这是我的登录代码
[HttpPost]
[Route("login")]
[AllowAnonymous]
public async Task<ActionResult> Login([FromForm]LoginRequest model)
model.ClientId = 1;
var response = await _services.GetTokenAsync(model);
if (response.StatusCode == 200)
return RedirectToAction("Index", "Home");
return RedirectToAction("Login");
这就是我要访问的内容
[HttpGet]
[Route("index")]
[Authorize]
public IActionResult Index()
return View();
【问题讨论】:
所提供的代码都不能帮助确定令牌正确存储的原因。您是否将其正确传递到后端? 似乎您已经显示了生成令牌的服务器代码。但是,您如何将其存储在客户端?您必须像 Postman 测试那样获取令牌并为每个服务调用提供它 @oleksa 似乎我没有获得令牌并将其发送到任何地方,因此我无法存储也无法使用它。你对此有什么方向吗?我只是 .NET core 的新成员,所以我不知道如何为每个需要它的函数提供令牌。谢谢。 @Mickers 不知道有没有传到后端,也许没有,你有没有指点,我真的不知道怎么做,谢谢. 通常您将令牌存储在前端的会话或本地存储中,然后在每个后续 API 调用中将其传递到标头中,例如token $token
。
【参考方案1】:
您需要创建自定义策略以在配置为使用自定义需求处理程序的 Authorize 属性中指定
首先,您通过继承IAuthorizationRequirement
的类列出自定义策略的要求
public class TokenRequirement : IAuthorizationRequirement
如果需要,您可以在此处选择接受参数。但通常您在请求的标头中传递一个令牌,您的自定义策略的需求处理程序无需显式参数即可访问该令牌。
您的自定义策略要使用的需求处理程序看起来像这样
public class TokenHandler : AuthorizationHandler<TokenRequirement>
//Some kind of token validator logic injected into your handler via DI
private readonly TokenValidator _tokenValidator;
//The http context of this request session also injected via DI
private readonly IHttpContextAccessor _httpCtx;
//The name of the header your token can be found under on a Http Request
private const string tokenHeaderKey = "authToken";
//Constructor using DI to get a instance of a TokenValidator class you would
//have written yourself, and the httpContext
public TokenHandler(TokenValidator tokenValidator, IHttpContextAccessor httpCtx)
_tokenValidator = tokenValidator;
_httpCtx = httpCtx;
//Overriden implementation of base class AuthorizationHandler's HandleRequirementAsync method
//This is where you check your token.
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context
,TokenRequirement requirement)
if (context.Resource is Endpoint endpoint)
HttpRequest httpReqCtx = _httpCtx.HttpContext.Request;
string token =
httpReqCtx.Headers.TryGetValue(tokenHeaderKey, out StringValues tokenVal)
? tokenVal.FirstOrDefault()
: null;
if (string.IsNullOrWhitespace(token))
context.Fail();
else
bool tokenIsValid = await _tokenValidator.ValidToken(token);
if(tokenIsValid)
context.Succeed(requirement);
else
context.Fail();
return Task.CompletedTask;
您可以像这样在 Startup.cs 中的自定义策略名称上注册自定义需求处理程序
//This is a framework extension method under Microsoft.Extensions.DependencyInjection
services.AddHttpContextAccessor();
//Your custom handler
services.AddSingleton<IAuthorizationHandler, TokenHandler>();
//Your custom policy
services.AddAuthorization(options =>
options.AddPolicy(
//Your custom policy's name, can be whatever you want
"myCustomTokenCheckerPolicy",
//The requirement your policy is going to check
//Which will be handled by the req handler added above
policy => policy.Requirements.Add(new TokenRequirement())
);
);
属性上的 impl 看起来像这样
[HttpGet]
[Route("index")]
[Authorize(Policy = "myCustomTokenCheckerPolicy")]
public IActionResult Index()
return View();
【讨论】:
非常感谢您的出色回答。我已尝试按照您的指示进行操作,但 HandleRequirementAsync 函数的 AuthorizationHandlerContext 上下文根本没有任何价值,因此令牌字符串始终返回 null。我不知道为什么。你有什么解决办法吗? 做一些快速的谷歌搜索,看起来 .Net Core 3 的情况略有变化,很抱歉造成混淆。我将更新我的答案以准确反映 .Net Core 3 所需的更改。 刚刚更新,抱歉花了一秒钟。另外,这是我发现的 SO 帖子,详细说明了 .NET Core 3 的实现差异。***.com/a/60417327/2293177 我想可能是因为TokenRequirement,我不知道为什么但是HandleRequirementAsync的token字符串总是返回null,非常感谢你的帮助! 有几件事可能会导致这种情况。我首先检查您是否实际上将令牌作为 HTTP 请求的标头传递。其次,如果您按照字母实现我的代码,我使用的标题键可能与您自己的不匹配。标头是键值对,它们通常看起来像 "apiToken": "1234-abcd" "apiToken" 是键,"1234-abcd" 是值。如果您尝试通过针对我的示例搜索名称为“authToken”的标头来获取令牌,那么您将得到 null,b/c 令牌在此实例中的名称为“apiToken”。所以我会检查你是否使用了正确的请求标头键以上是关于令牌无法存储在 .NET Core 中的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Asp Net Core Web App(不是 WebAPI)中存储令牌
使用 AspNetUserTokens 表在 ASP.NET Core Web Api 中存储刷新令牌
在 ASP.NET Core 2.1 Web 客户端中存储不记名令牌的位置
在 cookie 中存储 JWT 令牌后,如何在 ASP.NET Core 3.1 中破坏该 cookie 并获取信息