我没有使用任何默认的ASP.NET MVC身份验证,所以我使用cookie&创建自己的身份验证。为了我的安全,我的项目会话。下面的代码是我的函数Login,第一次生成cookie和会话。
HistoricScheduler
然后重定向到[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(User user)
{
bool ValidEmail = db.Users.Any(u => u.Username == user.Username);
if (!ValidEmail)
{
return RedirectToAction("Login", "Home");
}
string Password = db.Users.Where(u => u.Username == user.Username).Select(u => u.Password).Single();
user.Password = GenerateHashPassword(user.Password);
if (Password != user.Password)
{
return RedirectToAction("Login", "Home");
}
string AuthID = Guid.NewGuid().ToString();
Session["AuthID"] = AuthID;
var Cookie = new HttpCookie("AuthID");
Cookie.Values["AuthID"] = AuthID;
Cookie.Values["Username"] = user.Username;
Cookie.Values["LastVisit"] = DateTime.Now.ToString();
Cookie.Expires = DateTime.Now.AddDays(365);
Response.Cookies.Add(Cookie);
return RedirectToAction("Index", "Project");
}
。对于这个控制器中的每个函数,我做了一些if语句,如果Cookies不等于Session由相同的AuthID值,那么它会重定向到主页(登录前)。例如:
ProjectController
这可以防止未处于登录状态的用户无法访问该链接(例如[HttpGet]
public ActionResult Index()
{
try
{
if (Request.Cookies["AuthID"].Values["AuthID"] == Session["AuthID"].ToString())
{
// main code here ...
}
else
{
return RedirectToAction("Index", "Home");
}
}
catch
{
return RedirectToAction("Index", "Home");
}
}
[HttpGet]
public ActionResult Create()
{
try
{
if (Request.Cookies["AuthID"].Values["AuthID"] == Session["AuthID"].ToString())
{
// main code here ...
}
else
{
return RedirectToAction("Index", "Home");
}
}
catch
{
return RedirectToAction("Index", "Home");
}
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Project project)
{
try
{
if (Request.Cookies["AuthID"].Values["AuthID"] == Session["AuthID"].ToString())
{
// main code here ...
}
else
{
return RedirectToAction("Index", "Home");
}
}
catch
{
return RedirectToAction("Index", "Home");
}
}
[HttpGet]
public ActionResult Edit()
{
try
{
if (Request.Cookies["AuthID"].Values["AuthID"] == Session["AuthID"].ToString())
{
// main code here ...
}
else
{
return RedirectToAction("Index", "Home");
}
}
catch
{
return RedirectToAction("Index", "Home");
}
}
...
或localhost:60612/Project
或localhost:60612/Project/Create
等)并将重定向到主页。
这里的问题是如何最小化每个函数中重复的localhost:60612/Project/Edit/3
代码,记住一些软件质量保证方面:
如果有一些相同的确切代码,请在新函数中写入一次,然后通过其他需要的函数调用它(提取方法)。这样可以防止您的软件项目出现代码克隆或代码重复问题(Bad Smell),并提高您的软件性能质量
我该如何最小化此代码?或者还有其他解决方案吗?
答案 0 :(得分:1)
理想情况下,您希望使用 FormAuthentication ,它可以使用默认的 AuthorizeAttribute 。
由于您实现了自己的逻辑,因此您希望覆盖 AuthorizeAttribute 。
例如 -
public class MyAuthorizeAttribute : AuthorizeAttribute
{
private bool AuthorizeUser(AuthorizationContext filterContext)
{
bool isAuthorized = false;
if (filterContext.RequestContext.HttpContext != null)
{
var context = filterContext.RequestContext.HttpContext;
if (context.Session["AuthID"] != null &&
context.Request.Cookies["AuthID"].Values["AuthID"] ==
context.Session["AuthID"].ToString())
{
isAuthorized = true;
}
}
return isAuthorized;
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
throw new ArgumentNullException("filterContext");
if (AuthorizeUser(filterContext))
return;
base.OnAuthorization(filterContext);
}
}
[MyAuthorizeAttribute]
public class MyController : Controller
{
...
}
答案 1 :(得分:0)
我认为这通常是使用身份验证过滤器完成的。也许只是谷歌它,但这是一篇相关的文章http://www.dotnetcurry.com/aspnet-mvc/957/aspnet-mvc-authentication-filters
答案 2 :(得分:0)
应用于许多操作的通用逻辑通常应由操作过滤器处理 但是对于授权/认证案例,你真的应该使用一些经过验证和强化的广泛使用的解决方案,而不是实现自己的解决方案。
关于动作过滤器,基本的一般原则是从ActionFilterAttribute
派生,在其OnActionExecuting
方法中实现您的自定义通用逻辑,并将其应用于您的操作。有关一般情况的详细信息,请参阅here。
对于授权案例,使用您的自定义逻辑,您应该实现IAuthorizationFilter
。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,
Inherited = true, AllowMultiple = false)]
public class YourAuthorizationFilterAttribute :
FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
var httpContext = filterContext.HttpContext;
if (httpContext.Request.Cookies["AuthID"].Values["AuthID"] ==
httpContext.Session["AuthID"].ToString())
// Let the action get executed
return;
// Otherwise redirect
filterContext.Result = new RedirectResult(
filterContext.Controller.Url("Index", "Home"));
}
}
[YourAuthorizationFilter]
public ActionResult Index()
{
// main code here
}
为了避免使用此属性装饰大多数操作,您可以将其设置在控制器上或将其设置为全局过滤器(在需要身份验证的操作上不要忘记它的最佳解决方案)。
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new YourAuthorizationFilter());
...
但是,您可能需要一种方法来停用某些操作,例如登录操作。应该使用其他操作过滤器属性(例如YourAllowAnonymousAttribute
)来完成,该属性将由YourActionFilterAttribute
进行测试,如果存在,则YourAuthorizationFilter
将被停用。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,
Inherited = true, AllowMultiple = false)]
public class YourAllowAnonymousAttribute : ActionFilterAttribute
{
// Nothing to implement.
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,
Inherited = true, AllowMultiple = false)]
public class YourAuthorizationFilterAttribute :
FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.ActionDescriptor.IsDefined(
typeof(YourAllowAnonymousAttribute), inherit) ||
filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(
typeof(YourAllowAnonymousAttribute), true))
return;
...
public class HomeController : Controller
{
...
[YourAllowAnonymous]
public ActionResult Index()
{
...
从此answer中的AuthorizeFilter
派生不会将您重定向到您想要的“开箱即用”,您必须在web.config中配置Asp.Net表单身份验证(这就是为什么它提到“FormAuthentication”)。
另一种解决方案是使用自定义基本控制器并覆盖其OnActionExecuting
方法,但应首选操作过滤器。
但我坚持认为,实施自己的授权方案通常是一种反模式。安全是一件难事,这种逻辑有许多陷阱。也许这对你的应用程序来说根本不是问题,但以防万一:
HttpOnly
,以避免JavaScript能够访问它。Secure
,以避免以后通过不安全的HTTP进行传输。