似乎自定义授权属性可以工作。这是一个示例实现:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class RequiresSerialValidationAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
bool hasValidSerial = false;
if (filterContext.HttpContext.Request.IsAuthenticated)
{
string userName = filterContext.HttpContext.User.Identity.Name;
if (!string.IsNullOrWhiteSpace(userName))
{
string serial = string.Empty;// TODO: Retrieve user's previously authenticated serial, perhaps from Session or a cookie?
if(!string.IsNullOrWhiteSpace(serial))
{
var service = DependencyResolver.Current.GetService<IYourAuthService>();
hasValidSerial = service.IsSerialValidForUser(userName, serial);
}
}
}
if (!hasValidSerial)
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "yourserialauthcontroller", action = "yourauthaction", area = string.Empty }));
}
else
{
base.OnAuthorization(filterContext);
}
}
}
您可以使用此属性来装饰操作方法:
[RequireSerialValidation]
public ActionResult SomeAction()
{
}
该属性将触发重定向到您的质询操作,您将在其中提示用户输入其序列号。假设一切顺利,您将其序列存储在某处(会话可以在此处工作,或创建加密的 cookie),然后重定向回原始操作。在第二次尝试中,您已经验证了该操作是允许的,因此不会发生重定向。
您的身份验证服务可以是您想要的任何服务。在此示例中,我假设您正在使用依赖项注入并且已配置全局依赖项解析器。鉴于此,您的 IYourAuthService 可能如下所示(省略其他方法):
public IYourAuthService
{
bool IsSerialValidForUser(string userName, string serial);
}
像这样的实现:
public YourAuthService : IYourAuthService
{
public bool IsSerialValidForUser(string userName, string serial)
{
using(var context = new YourEntityFrameworkDbContext())
{
return context.Users.Any(u => u.UserName.Equals(userName, StringComparison.OrdinalIgnoreCase) && u.Serial.Equals(serial, StringComparison.OrdinalIgnoreCase));
}
}
}
这假设您有一个名为User
(or Users
)在你的数据库中,并且UserName
and Serial
是该表上的字段。StringComparison.OrdinalIgnoreCase https://msdn.microsoft.com/en-us/library/system.stringcomparison.aspx允许您对尝试比较的字符串进行不区分大小写、不区分区域性的匹配。