問題描述
MVC 授權 ‑ 多個登錄頁面 (MVC Authorization ‑ multiple login pages)
I have a the following methods in an MVC Controller which redirect to the login page when a user is not logged in.
[Authorize]
public ActionResult Search() {
return View();
}
[Authorize]
public ActionResult Edit() {
return View();
}
Is there a quick/easy/standard way to redirect the second action to a different login page other than the page defined in the web.config file?
Or do I have to do something like
public ActionResult Edit() {
if (IsUserLoggedIn)
return View();
else
return ReturnRedirect("/Login2");
}
‑‑‑‑‑
參考解法
方法 1:
I think it is possible by creating a custom authorization filter:
public class CustomAuthorization : AuthorizeAttribute
{
public string LoginPage { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.HttpContext.Response.Redirect(LoginPage);
}
base.OnAuthorization(filterContext);
}
}
In your action:
[CustomAuthorization(LoginPage="~/Home/Login1")]
public ActionResult Search()
{
return View();
}
[CustomAuthorization(LoginPage="~/Home/Login2")]
public ActionResult Edit()
{
return View();
}
方法 2:
Web.config
based forms authentication does not have such a functionality built‑in (this applies to both WinForms and MVC). You have to handle it yourself (either through an HttpModule or ActionFilter, the method you mentioned or any other method)
方法 3:
I implemented the accepted answer by user434917 and even though I was being redirected correctly, I was also receiving the error "Server cannot set status after HTTP headers have been sent." in the server log. After searching, I found this post (answer by Mattias Jakobsson) that solved the problem. I combined the answers to get this solution.
Create a custom authorization filter:
using System.Web.Mvc;
using System.Web.Routing;
namespace SomeNamespace.CustomFilters
{
public class CustomAuthorization : AuthorizeAttribute
{
public string ActionValue { get; set; }
public string AreaValue { get; set; }
public string ControllerValue { get; set; }
public override void OnAuthorization(AuthorizationContext context)
{
base.OnAuthorization(context);
if (context.HttpContext.User.Identity.IsAuthenticated == false)
{
var routeValues = new RouteValueDictionary();
routeValues["area"] = AreaValue;
routeValues["controller"] = ControllerValue;
routeValues["action"] = ActionValue;
context.Result = new System.Web.Mvc.RedirectToRouteResult(routeValues);
}
}
}
}
Then on your controller, use the customer attribute.
[CustomAuthorization(ActionValue = "actionName", AreaValue = "areaName", ControllerValue = "controllerName")]
public class SomeControllerController : Controller
{
//DO WHATEVER
}
方法 4:
Yeah pretty easy! Lets say you have 2 different type of users. First typenormal users, the other one is administrators. You would like to make them login from different pages. You also want them to be able to access different ActionResults.
First you have add two different schemes. In these schemes you will define your different login pages and other options you want.
in startup.cs
services.AddAuthentication("UserSceheme").AddCookie("UserScheme", config =>
{
config.LoginPath = "/UsersLogin/Login/";
config.Cookie.Name = "UsersCookie";
});
services.AddAuthentication("AdminScheme").AddCookie("AdminScheme", config =>
{
config.LoginPath = "/AdminLogin/Login/";
config.Cookie.Name = "AdminsCookie";
});
Then you will define two policies. Here I called them UserAccess and AdminAccess Each policy will use the sceheme that I point. In startup.cs just after schemes add those below.
services.AddAuthorization(options =>
{
options.AddPolicy("UserAccess", policy =>
{
policy.AuthenticationSchemes.Add("UserScheme");
policy.RequireAuthenticatedUser();
});
options.AddPolicy("AdminAccess", policy =>
{
policy.AuthenticationSchemes.Add("AdminScheme");
policy.RequireAuthenticatedUser();
});
});
The last thing we have to do is again telling the scheme we want to use when login.
var userPrincipal = new ClaimsPrincipal(new[] {
new ClaimsIdentity(loginClaims, "ServiceCenter")
});
HttpContext.SignInAsync("AdminScheme",userPrincipal);
Thats it! Now we can use these just like this; This will redirect you to the users login page.
[Authorize(Policy = "UserAccess")]
public IActionResult Index()
{
return View();
}
If you have some places that you want both user types to be able to access all you have to do;
[Authorize(Policy = "AdminAccess")]
[Authorize(Policy = "UserAccess")]
public IActionResult Index()
{
return View();
}
And finally for log‑out you also have to point the scheme
public async Task<IActionResult> Logout()
{
await HttpContext.SignOutAsync("AdminScheme");
return View();
}
Thats it!
(by David Glenn、user434917、mmx、joeshmoe301、meybivi)