ASP.NET MVC 3 с использованием аутентификации
Как я могу сохранить что-то с помощью FormsAuthentication? Я не хочу хранить UserId через URL.
Например, теперь у меня есть этот код:
//UserController class:
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (repository.ValidateUser(model.Login, model.Password))
{
FormsAuthentication.SetAuthCookie(model.Login, model.RememberMe);
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Project", "Index");
}
}
else
{
ModelState.AddModelError("", "Incorrect name or password.");
}
}
return View(model);
}
ProjectController
класс:
public ViewResult Index()
{
return View(repository.GetUserProjects(
this.ControllerContext.HttpContext.User.Identity.Name));
}
ProjectRepository
:
ProjectsContext context = new ProjectsContext();
UsersContext uCnt = new UsersContext();
public IEnumerable<Project> GetUserProjects(String username)
{
if (String.IsNullOrEmpty(username))
throw new ArgumentNullException("username", "Login is empty");
return this.uCnt.Users
.FirstOrDefault(u => u.Login == username)
.Projects
.ToList();
}
ProjectController и ProjectRepository не похожи на хороший код... Может быть, кто-то может дать совет, как хранить UserID без использования URL? Лучший способ сделать это - сохранить идентификаторы при авторизации, я думаю. Я не нашел никаких свойств в User.Identity, чтобы сделать это...
UPD
Прошу прощения, но я забыл сказать, что использую MVC-3 с видом Razor.
И этот UserId не является строкой (User.Identity.Name - это строка), это может быть GUID или, может быть, мой собственный объект...
Ответы
Ответ 1
Сохраните UserID в свойстве UserData бита FormsAuthentication в файле cookie авторизации при входе пользователя в систему:
string userData = userID.ToString();
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, user.Email,
DateTime.Now, DateTime.Now.AddMinutes(FormsAuthentication.Timeout.TotalMinutes),
createPersistentCookie, userData);
string hashedTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hashedTicket);
HttpContext.Current.Response.Cookies.Add(cookie);
Вы можете прочитать его обратно в методе PostAuthenticateRequest в Global.asax:
HttpCookie formsCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (formsCookie != null)
{
FormsAuthenticationTicket auth = FormsAuthentication.Decrypt(formsCookie.Value);
Guid userID = new Guid(auth.UserData);
var principal = new CustomPrincipal(Roles.Provider.Name, new GenericIdentity(auth.Name), userID);
Context.User = Thread.CurrentPrincipal = principal;
}
Обратите внимание, что в этом случае CustomPrincipal происходит из RolePrincipal (хотя, если вы не используете роли, я думаю, вам нужно извлечь из GenericPrincipal) и просто добавляет свойство UserID и перегружает конструктор.
Теперь, где вам нужен UserID в вашем приложении, вы можете сделать это:
if(HttpContext.Current.Request.IsAuthenticated)
Guid userID = ((CustomPrincipal)HttpContext.Current.User).UserID;
Ответ 2
Почему бы не сначала выполнить все ваши авторизационные вызовы через интерфейс. Таким образом, весь ваш код, который использует аутентификацию, не должен беспокоиться о том, как выполняется вход в систему, или о том, как хранится Indentity и т.д.
public interface IAuthorization
{
bool ValidateUser(LoginUser u, string password);
LoginUser GetCurrentUser();
void LogIn(LoginUser user);
void LogOut();
IIdentity GetCurrentUserIdentity();
}
Исполнение для IIdentity GetCurrentUserIdentity может быть любым, как вам нравится, но обычно рассматривается как вызов "HttpContext.Current.User.Identity"
public class Authorization : IAuthorization
{
/// <summary>
/// Get the IIdentity for the current logged in user
/// </summary>
/// <returns>IIdentity</returns>
public virtual IIdentity GetCurrentUserIdentity()
{
return HttpContext.Current.User.Identity;
}
/// <summary>
/// Log the user in
/// </summary>
/// <param name="user">User details</param>
public void LogIn(LoginUser user)
{
InvalidCredentialsOnNullUser(user);
FormsAuthentication.SetAuthCookie(user.Name, false);
}
/// <summary>
/// Log the user out
/// </summary>
public void LogOut()
{
FormsAuthentication.SignOut();
}
private static void InvalidCredentialsOnNullUser(LoginUser user)
{
if (user == null)
{
throw new InvalidCredentialException("That user doesn't exist or is not valid.");
}
}
// other methods....
}
Класс LoginUser, который вы видите, представляет собой информацию, полученную о пользователе членства. Это обычно делается через MemberhipProvider, но, конечно, это можно сделать другими способами.
public class LoginUser
{
public string Name;
public Guid Key;
public string EmailAddress;
public bool IsApproved;
public bool IsLockedOut;
public DateTime CreationDate;
public DateTime? LastLoginDate;
public DateTime? LastPasswordChangedDate;
}
Ответ 3
Я не уверен, что правильно понял вопрос, но если вы ссылаетесь на способ получения того, кто текущий пользователь, не передавая его через URL (например, http://localhost/controller/action?username=RAMe0), вы можете посмотреть на использование Thread.CurrentPrincipal.Identity.Name или HttpContext.Current.User
Между ними существуют тонкие различия. Посмотрите здесь для более подробной информации.
Ответ 4
Используя FormsAuthentication
, вы можете сохранить имя пользователя в свойстве User.Identity.Name
. Вот простой пример того, что вы, вероятно, ищете. (Используя тот же SetAuth
, который вы уже используете)
public ViewResult Index() {
return View(repository.GetUserProjects(this.User.Identity.Name));
}
Это не требует, чтобы вы передавали имя пользователя через параметр QueryString.