我有一个MVC 5应用程序,其控制器具有[Authorize]
属性。但是,要求声明客户端可能无法登录到Web应用程序(因为此Web应用程序将部署在标牌播放器上 - 而不是Web浏览器 - 接受URL作为输入以访问Web应用程序中的特定操作)。 / p>
作为回应,我正在考虑使用客户端可以使用的URL来授权他们的操作,而不是登录...格式为:
http://{website}/Action?token={/* randomly generated key for this user */}
如何在不改变使用[Authorize]
属性的当前代码的情况下实现此目的?
答案 0 :(得分:0)
我确实稍微更改了我的代码。我没有用[Authorize]
打扮我的控制器,而是创建了一个名为[TokenAuthorize]
的{{3}}。
我创建了一个SecurityManager
类来生成和验证令牌。这是从custom authorize attribute改编而来的,尽管我选择不使用任何客户端代码或使用ip
或userAgent
哈希。另外,我创建了一个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}}