ASP.NET MVC Создание олицетворенного пользователя
-
23-09-2019 - |
Вопрос
У меня есть приложение MVC, в котором у меня есть класс User, и пользователь также может выдавать себя за другого пользователя (только для пользователей с правами администратора).
Итак, у меня есть код ниже, который аутентифицирует запрос и создает экземпляр моей версии класса User.
Затем он пытается получить олицетворенного пользователя из объекта Session, но сеанс недоступен в этом методе в файле global.asax.
Надеюсь, это имеет смысл.
Как еще я мог это сделать?
Я думаю, мой вопрос заключается в том, в какой момент методов global.asax вы получаете доступ к объекту Session для каждого запроса?
protected void Application_OnAuthenticateRequest(object sender, EventArgs e)
{
IMylesterService service = ObjectFactory.GetInstance<IMylesterService>();
if (Context.User != null)
{
if (Context.User.Identity.IsAuthenticated)
{
User user = service.GetUser(Context.User.Identity.Name);
if (user == null)
throw new ApplicationException("Context.user.Identity.name is not a recognized user");
User impersonatedUser = (User)this.Session["ImpersonatedUser"];
if (impersonatedUser == null)
user.ImpersonatedUser = user;
else
user.ImpersonatedUser = impersonatedUser;
System.Threading.Thread.CurrentPrincipal = Context.User = user;
return;
}
}
User guest = service.GetGuestUser();
guest.ImpersonatedUser = guest;
System.Threading.Thread.CurrentPrincipal = Context.User = guest;
}
Нет правильного решения
Другие советы
Попробуйте создать фильтр авторизации:
public class CustomAuthorizationFilter : AuthorizeAttribute
{
protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
{
// perform your authorization here
// full access to HttpContext and session
}
}
Затем вы можете применить этот атрибут к своим контроллерам.В идеале у вас должен быть базовый контроллер, от которого наследуются все остальные контроллеры, и вы могли бы применить атрибут на уровне класса к этому контроллеру.Тогда все ваши запросы будут авторизованы и применено олицетворение, как вы написали выше.
Сессия не будет доступна во время AuthenticateRequest:Вам нужно будет пометить необходимую информацию в Identity.userData;например, если вы используете аутентификацию с помощью форм, выполните следующие действия:
void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (Context.User != null)
{
if (Context.User.Identity.IsAuthenticated)
{
// retrieve the value
var id = (FormsIdentity)Context.User.Identity;
var myvalue = id.Ticket.UserData; // "Here you are"
}
}
}
Для входа в систему с помощью форм вам необходимо написать собственный файл cookie:MVC → класс FormsAuthenticationService:IFormsAuthenticationService
public static void SetAuthenticationCookie(HttpContextBase context, FormsAuthenticationTicket ticket)
{
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName)
{
Value = FormsAuthentication.Encrypt(ticket),
Secure = FormsAuthentication.RequireSSL,
Domain = FormsAuthentication.CookieDomain,
HttpOnly = true,
Expires = DateTime.Now.AddMinutes(15)
};
if (!context.Request.IsSecureConnection && FormsAuthentication.RequireSSL)
{
throw new HttpException("Ticket requires SSL.");
}
context.Response.Cookies.Add(cookie);
}
public static FormsAuthenticationTicket CreateTicket(HttpContextBase context, string emailAddress, string userData, bool persist)
{
return new FormsAuthenticationTicket(1, emailAddress, DateTime.Now, DateTime.Now.AddMinutes(15), persist, userData, FormsAuthentication.FormsCookiePath);
}
Наконец, в SignIn вы теперь должны создать необходимый билет, вызвав CreateTicket(...), а затем записать его с помощью SetAuthenticationCookie(...).
public void SignIn(string userName, string password)
{
if(CheckUserValid(userName,password, out string email))
{
var ticket = CreateTicket(email, "Here you are", true);
SetAuthenticationCookie(HttpContext.Current.Base(), ticket);
}
}
Я никогда его не использовал, но предполагаю, что состояние сеанса назначается во время AcquireRequestState:
public void Init(HttpApplication context)
{
context.AcquireRequestState += new EventHandler(context_AcquireRequestState);
}
У меня была такая же проблема с доступом к сеансу в global.asax, и я, наконец, решил ее, переместив свой код в AcquireRequestState
обработчик, который происходит после прохождения аутентификации.
protected void Application_AcquireRequestState(Object sender, EventArgs e)
{
if (Request.IsAuthenticated && Context.Session != null)
{
// access Context.Session
}
}
Это часто срабатывает, и текущий контекст не всегда имеет действительный объект сеанса, следовательно, проверка.
РЕДАКТИРОВАТЬ:Пришлось также добавить проверку IsAuthenticated - при выходе из системы получала нулевую ошибку.Отлично работает сейчас.