ユーザーの役割に基づいてユーザーをページにリダイレクトしようとしていますが、
これは、ASP.NET MVC 5に付属するログイン関数のデフォルトの実装です。
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindAsync(model.UserName, model.Password);
if (user != null)
{
await SignInAsync(user, model.RememberMe);
return RedirectToLocal(returnUrl);
}
else
{
ModelState.AddModelError("", "Invalid username or password.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
private ActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Employer");
}
}
ユーザーの役割に基づいてユーザーをリダイレクトできるようにしたいので、次のようにしてみました。
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindAsync(model.UserName, model.Password);
if (user != null)
{
await SignInAsync(user, model.RememberMe);
//role Employer go to Employer page
if (UserManager.IsInRole(user.Id, "Employer"))
{
return RedirectToAction("Index", "Employer");
}
//role Admin go to Admin page
else if (UserManager.IsInRole(user.Id, "Admin"))
{
return RedirectToAction("Index", "Admin");
}
else
{
//no role
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "Invalid username or password.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
しかし、問題があります。サイトが正しいページにリダイレクトしていますが、管理者アカウントでログインしていないときにfoo.com/adminのURLを入力してナビゲートすると、サイトは次のようなログインページに移動します。 URL foo.com/Account/Login?ReturnUrl=%2Fadmin、これは予想される動作です。
この時点で雇用主のアカウントでログインすると、雇用主のページにリダイレクトされ、雇用主としてログインしますが、これは間違いではありませんが、そうではないはずです。戻りURLが「admin」であるため、代わりに管理者アカウント。私は理にかなっていると思います。
カスタムリダイレクトの前にreturnUrlがあるかどうかを確認しないのはなぜですか?
_ [HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindAsync(model.UserName, model.Password);
if (user != null)
{
await SignInAsync(user, model.RememberMe);
if (String.IsNullOrEmpty(returnUrl))
{
if (UserManager.IsInRole(user.Id, "Employer"))
{
return RedirectToAction("Index", "Employer");
}
//role Admin go to Admin page
if (UserManager.IsInRole(user.Id, "Admin"))
{
return RedirectToAction("Index", "Admin");
}
}
else
{
return RedirectToLocal(returnUrl);
}
}
else
{
ModelState.AddModelError("", "Invalid username or password.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
_
このようにfoo.com/adminに移動すると、401がスローされ、ログインにリダイレクトされます。次に、雇用者としてログインすると、401がスローされ、再度ログインするようにリダイレクトされます。
コメントから:「Redirect(returnUrl)を実行してRedirectToLocalアクションメソッドを削除できますか?」
RedirectToLocal(returnUrl)
メソッドは、Url.IsLocalUrl(returnUrl)
かどうかをチェックします。したがって、オープンリダイレクト攻撃を防ぐために必要です。
[ this ]の記事は2008年に書かれていますが、この問題の解決に役立ちました。 Loginメソッドを混乱させることなく、ログイン時にユーザーをリダイレクトするために必要なすべてのコードサンプルを提供します。新しいロールを追加して、そのロールを持つユーザーをリダイレクトする場合は、web.configに行を追加するだけです。
私は1つの問題に出くわしました。彼の記事には、AccountController(またはリダイレクトを実行する場所)に配置する次のコードが含まれています。
/// <summary>
/// Redirect the user to a specific URL, as specified in the web.config, depending on their role.
/// If a user belongs to multiple roles, the first matching role in the web.config is used.
/// Prioritize the role list by listing higher-level roles at the top.
/// </summary>
/// <param name="username">Username to check the roles for</param>
private void RedirectLogin(string username)
{
LoginRedirectByRoleSection roleRedirectSection = (LoginRedirectByRoleSection)ConfigurationManager.GetSection("loginRedirectByRole");
foreach (RoleRedirect roleRedirect in roleRedirectSection.RoleRedirects)
{
if (Roles.IsUserInRole(username, roleRedirect.Role))
{
Response.Redirect(roleRedirect.Url);
}
}
}
アプリケーションがロールプロバイダーを見つけることができず、web.configに追加したときに、ロールを見つけるのに苦労しました。私はロールプロバイダーを廃止し、UserManagerを使用してユーザーとロールを取得することにしました。
/// <summary>
/// Redirect the user to a specific URL, as specified in the web.config, depending on their role.
/// If a user belongs to multiple roles, the first matching role in the web.config is used.
/// Prioritize the role list by listing higher-level roles at the top.
/// </summary>
/// <param name="username">Username to check the roles for</param>
private void RedirectLogin(string username)
{
LoginRedirectByRoleSection roleRedirectSection = (LoginRedirectByRoleSection)ConfigurationManager.GetSection("loginRedirectByRole");
var user = UserManager.FindByName(username);
var rolesForUser = UserManager.GetRoles(user.Id);
foreach (RoleRedirect roleRedirect in roleRedirectSection.RoleRedirects)
{
if (rolesForUser.Contains(roleRedirect.Role))
{
Response.Redirect(roleRedirect.Url);
}
}
}