使用URL参数授权操作

时间:2016-02-01 15:06:21

标签: url authentication asp.net-mvc-5 authorization

我有一个MVC 5应用程序,其控制器具有[Authorize]属性。但是,要求声明客户端可能无法登录到Web应用程序(因为此Web应用程序将部署在标牌播放器上 - 而不是Web浏览器 - 接受URL作为输入以访问Web应用程序中的特定操作)。 / p>

作为回应,我正在考虑使用客户端可以使用的URL来授权他们的操作,而不是登录...格式为:

http://{website}/Action?token={/* randomly generated key for this user */}

如何在不改变使用[Authorize]属性的当前代码的情况下实现此目的?

1 个答案:

答案 0 :(得分:0)

我确实稍微更改了我的代码。我没有用[Authorize]打扮我的控制器,而是创建了一个名为[TokenAuthorize]的{​​{3}}。

我创建了一个SecurityManager类来生成和验证令牌。这是从custom authorize attribute改编而来的,尽管我选择不使用任何客户端代码或使用ipuserAgent哈希。另外,我创建了一个TokenIdentity类来创建Identity来授权操作。这是改编自Primary Objects。 Jelle的Steve's Coding Blog还使用GenericPrincipal HttpContext.Current.User = new GenericPrincipal(new TokenIdentity(username), roles.ToArray());来帮助用户授权用户:token

执行此操作后,我能够使用名为http://{website}/Action?token={/* randomly generated key for this user */}的url参数授权操作:public class TokenAuthorize : AuthorizeAttribute { private const string SecurityToken = "token"; public override void OnAuthorization(AuthorizationContext filterContext) { if (Authorize(filterContext)) { return; } HandleUnauthorizedRequest(filterContext); } private bool Authorize(AuthorizationContext actionContext) { try { HttpContextBase context = actionContext.RequestContext.HttpContext; string token = context.Request.Params[SecurityToken]; // check if the token is valid. if so, authorize action. bool isTokenAuthorized = SecurityManager.IsTokenValid(token); if (isTokenAuthorized) return true; // if the token is not valid, check if the user is authorized by default. bool isDefaultAuthorized = AuthorizeCore(context); return isDefaultAuthorized; } catch (Exception) { return false; } } }

<强> link

public class SecurityManager
{
    private const string Alg = "HmacSHA256";
    private const string Salt = "rz8LuOtFBXphj9WQfvFh";

    // Generates a token to be used in API calls.
    // The token is generated by hashing a message with a key, using HMAC SHA256.
    // The message is: username
    // The key is: password:salt
    public static string GenerateToken(string username, string password)
    {
        string hash = string.Join(":", new string[] { username });
        string hashLeft;
        string hashRight;

        using (HMAC hmac = HMAC.Create(Alg))
        {
            hmac.Key = Encoding.UTF8.GetBytes(GetHashedPassword(password));
            hmac.ComputeHash(Encoding.UTF8.GetBytes(hash));

            hashLeft = Convert.ToBase64String(hmac.Hash);
            hashRight = string.Join(":", username);
        }

        return Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Join(":", hashLeft, hashRight)));
    }

    // used in generating a token
    private static string GetHashedPassword(string password)
    {
        string key = string.Join(":", new string[] { password, Salt });

        using (HMAC hmac = HMAC.Create(Alg))
        {
            // Hash the key.
            hmac.Key = Encoding.UTF8.GetBytes(Salt);
            hmac.ComputeHash(Encoding.UTF8.GetBytes(key));

            return Convert.ToBase64String(hmac.Hash);
        }
    }

    // Checks if a token is valid.
    public static bool IsTokenValid(string token)
    {
        var context = new ApplicationDbContext();

        try
        {
            // Base64 decode the string, obtaining the token:username.
            string key = Encoding.UTF8.GetString(Convert.FromBase64String(token));

            // Split the parts.
            string[] parts = key.Split(':');
            if (parts.Length != 2) return false;

            // Get the username.
            string username = parts[1];

            // Get the token for said user
            // var computedToken = ...

            // Compare the computed token with the one supplied and ensure they match.
            var result = (token == computedToken);

            if (!result) return false;

            // get roles for user (ASP.NET Identity 2.0)
            var user = context.Users.Single(u => u.UserName == username);
            var rolesPerUser = context.UserRoles.Where(x => x.UserId == user.Id).ToList();
            var roles = rolesPerUser.Select(role => context.Roles.Single(r => r.Id == role.RoleId).Name);
            // NOTE: define public DbSet<IdentityUserRole> UserRoles { get; set; } ...
            // ... in your DbContext in IdentityModels.cs

            HttpContext.Current.User = new GenericPrincipal(new TokenIdentity(username), roles.ToArray());

            return true;
        }
        catch
        {
            return false;
        }
    }
}

SecurityManager.cs TokenAuthorize.cs

public class TokenIdentity : IIdentity
{
    public string User { get; private set; }

    public TokenIdentity(string user)
    {
        this.User = user;
    }

    public string Name => User;

    public string AuthenticationType => "ApplicationToken";

    public bool IsAuthenticated => true;
}

TokenIdentity.cs adapted from Primary Objects

{{1}}