使用ASP.NET MVC在查询字符串中使用auth令牌对用户进行身份验证

时间:2013-03-07 07:44:34

标签: asp.net-mvc authentication asp.net-mvc-4 forms-authentication

[这个问题与ASP.NET MVC4有关,它是关于最佳实践的方法 - 所以请不要暗示黑客攻击。]

我想使用请求网址中发送的身份验证令牌对用户进行身份验证。它与密码重置令牌的工作方式类似,但在这种情况下,它不会转到重置页面,而是授予对站点某些部分的访问权限。我们的想法是将带有身份验证令牌的URL发送到用户的经过验证的电子邮件地址。用户可以单击该链接并执行某些操作,而无需键入密码。

开箱即用,ASP.NET具有[Authorize]属性和SimpleMembershipProvider - 这些似乎工作得很好,但是他们在引擎盖下做了一些巫术魔法(比如自动生成数据库表),所以我不知道如何扩展它们以添加这个基于链接的身份验证令牌。

我不希望得到确切答案,但请指出正确的方向。

谢谢!

3 个答案:

答案 0 :(得分:2)

Uf,广泛的问题。但我会尝试至少指引你走向正确的方向。

首先,如果建议您使用表单身份验证作为基础,但您必须自定义使用它。我认为您不希望使用cookie进行身份验证,因为这是表单身份验证的本机行为。

您应该考虑的最重要的一点是自定义查询字符串令牌的身份验证。

  1. 创建登录操作,在此操作中,您将授权用户,如果他已授予访问权限,则要求FormsAuthentication创建AuthCookie。更进一步,您只需将httpCookie.Value作为您的身份验证令牌,您将在查询字符串中携带。

  2. 您需要在Application_BeginRequest中实施Global.asax来处理此查询字符串令牌,并将其转换为Cookie 。使用此方法,您可以利用所有ASP.NET Forms身份验证基础结构。

  3. 这是非常高级别的图片,没有代码。如果您需要更多细节帮助,我也可以提供给您。

答案 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.
                }
            }
        }

我用过: jwt-dotnet/jwt library 7.2.1