[这个问题与ASP.NET MVC4有关,它是关于最佳实践的方法 - 所以请不要暗示黑客攻击。]
我想使用请求网址中发送的身份验证令牌对用户进行身份验证。它与密码重置令牌的工作方式类似,但在这种情况下,它不会转到重置页面,而是授予对站点某些部分的访问权限。我们的想法是将带有身份验证令牌的URL发送到用户的经过验证的电子邮件地址。用户可以单击该链接并执行某些操作,而无需键入密码。
开箱即用,ASP.NET具有[Authorize]属性和SimpleMembershipProvider - 这些似乎工作得很好,但是他们在引擎盖下做了一些巫术魔法(比如自动生成数据库表),所以我不知道如何扩展它们以添加这个基于链接的身份验证令牌。
我不希望得到确切答案,但请指出正确的方向。
谢谢!
答案 0 :(得分:2)
Uf,广泛的问题。但我会尝试至少指引你走向正确的方向。
首先,如果建议您使用表单身份验证作为基础,但您必须自定义使用它。我认为您不希望使用cookie进行身份验证,因为这是表单身份验证的本机行为。
您应该考虑的最重要的一点是自定义查询字符串令牌的身份验证。
创建登录操作,在此操作中,您将授权用户,如果他已授予访问权限,则要求FormsAuthentication创建AuthCookie。更进一步,您只需将httpCookie.Value作为您的身份验证令牌,您将在查询字符串中携带。
您需要在Application_BeginRequest
中实施Global.asax
来处理此查询字符串令牌,并将其转换为Cookie 。使用此方法,您可以利用所有ASP.NET Forms身份验证基础结构。
这是非常高级别的图片,没有代码。如果您需要更多细节帮助,我也可以提供给您。
答案 1 :(得分:1)
您应该使用接受Action
的常规HttpGet
。
收到令牌后,立即使其无效,因此无法再次使用。
此外,只接受在预定义的时间段范围内的令牌,例如24或72小时。
答案 2 :(得分:0)
谢谢彼得的想法。
如果smb需要为旧的ASP.NET MVC5创建JWT令牌授权,我写了一个小例子。我不将cookie序列化为JWT。我创建了一个JWT,并在BeginRequest中对其进行了检查。如果一切正常,我创建一个cookie并将其设置为httpContext.Request。我为应用程序使用了身份验证模式=“表单”,它需要cookie。
用于创建JWT令牌:
const string secret = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk";
[AllowAnonymous]
[HttpPost]
public ActionResult LoginJWT(LoginViewModel model)
{
ActionResult response = null;
if (ModelState.IsValid)
{
if (true) //todo: check user login&password
{
var payload = new Dictionary<string, object>
{
{ "iss", "subject" },
{ "sub", "api" },
{ "exp", DateTimeOffset.UtcNow.AddHours(2).ToUnixTimeSeconds()},
{ "iat", DateTimeOffset.UtcNow.ToUnixTimeSeconds()},
{ "jti", Guid.NewGuid() },
{ "uid", "64" } //custom field for identificate user
};
IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); // symmetric
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
var token = encoder.Encode(payload, secret);
response = Content(token);
}
else
{
response = new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest, "Login or password are not found");
}
}
else
{
response = new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest, "Errors in Model");
}
return response;
}
在Global.asax中检查JWT令牌:
public override void Init()
{
this.BeginRequest += this.BeginRequestHandler;
base.Init();
}
private void BeginRequestHandler(object sender, EventArgs e)
{
var bearerToken = this.Context.Request.Headers["Authorization"];
if (bearerToken != null)
{
var token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;
const string secret = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk";
int userId = 0;
try
{
IJsonSerializer serializer = new JsonNetSerializer();
var provider = new UtcDateTimeProvider();
IJwtValidator validator = new JwtValidator(serializer, provider);
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); // symmetric
IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm);
var json = decoder.DecodeToObject<IDictionary<string, string>>(token, secret, verify: true);
if (json.TryGetValue("uid", out var uid))
{
userId = Convert.ToInt32(uid);
}
}
catch (TokenExpiredException)
{
Console.WriteLine("Token has expired");
}
catch (SignatureVerificationException)
{
Console.WriteLine("Token has invalid signature");
}
if (userId != 0)
{
// check user by id, if found create cookie.
}
}
}