인증 된 사용자보다 높은 수준에서이를 추상화해야합니다. 로그인 한 사용자와 현재 사용자의 개념을 소개하는 것이 좋습니다. 세션은 로그인 한 사용자와 유지되지만 충분한 권한을 가진 로그인 한 사용자는 다른 사용자를 가장 할 수 있으며 해당 사용자는 현재 사용자가됩니다. 현재 사용자를 사용하여 데이터에 대한 액세스를 제어하고 (가장하는 사용자가 가장을 제어해야하는 경우를 제외하고) UI를 구동하고, 트랜잭션을 수행합니다. 세션에서 현재 사용자를 데이터로 저장합니다. 필요한 경우 OnActionExecuting의 기본 컨트롤러
public class AdminController : BaseController
{
[Authorize(Roles = "ActOnBehalfOfUser")]
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Impersonate()
{
return View();
}
[Authorize(Roles = "ActOnBehalfOfUser")]
[AcceptVerbs(HttpVerbs.Post)]
[ValidateAntiForgeryToken]
public ActionResult Impersonate(string userNameOrID, bool? revoke)
{
var currentUser = this.GetCurrentUser();
if (revoke.HasValue && revoke.Value)
{
try
{
LogImpersonationEnd(currentUser);
}
catch { }
this.SetEffectiveUser(currentUser);
}
else
{
if (string.IsNullOrEmpty(userNameOrID))
{
this.ModelState.AddModelError("userNameOrID", "You must supply a username or uid to impersonate.");
return View();
}
var person = this.LookupUser(userNameOrID);
if (person == null)
{
this.ModelState.AddModelError("userNameOrID", "No user with the given id was found.");
return View();
}
this.SetEffectiveUser(person);
try
{
using (var dc = new FooDataContext())
{
var impersonation = new Impersonation
{
EffectiveUser = person.UID,
ActualUser = currentUser.UID
};
dc.InsertOnSubmit(impersonation);
dc.SubmitChanges();
}
}
catch { }
}
return View();
}
}
자료 컨트롤러 :
public class BaseController : Controller
{
protected bool IsImpersonating
{
get
{
var effectiveUID = this.Session[EFFECTIVE_USER_KEY] as string;
var uid = this.Session[USER_KEY] as string;
return !string.Equals(effectiveUID, uid);
}
}
protected Person GetEffectiveUser()
{
return GetUser(this.Session[EFFECTIVE_USER_KEY] as string);
}
protected void SetEffectiveUser(Person person)
{
this.Session[EFFECTIVE_USER_KEY] = person.UniversityID;
this.Session[UIPERSON_KEY + person.UniversityID] = person;
}
protected Person GetUser(string uid)
{
Person person = null;
if (!string.IsNullOrEmpty(uid))
{
person= GetCachedPerson(uid, p => p.UID == uid);
}
return person ?? new AnonymousPerson();
}
protected Person LookupUser(string usernameOrUID)
{
Person person = null;
if (!string.IsNullOrEmpty(usernameOrUID))
{
uiPerson = this.GetCachedPerson(usernameOrUID, p => p.UID== usernameOrUID || p.Username == usernameOrUID);
}
return uiPerson;
}
private Person GetCachedPerson(string uid, Expression<Func<Person, bool>> selector)
{
Person person = this.Session[PERSON_KEY + uid] as Person;
if (person == null)
{
using (var context = new FooDataContext())
{
person = context.SingleOrDefault<Person>(selector);
if (uiPerson != null)
{
this.Session[PERSON_KEY + uid] = person;
}
}
}
return person;
}
protected void LogImpersonationEnd(Person currentUser)
{
using (var dc = new FooDataContext())
{
var euid = this.GetEffectiveUser().UID;
var impersonation = dc.Table<Impersonation>()
.Where(i => i.EffectiveUser == euid && i.ActualUser == currentUser.UniversityID && !i.EndTime.HasValue)
.OrderByDescending(i => i.ID)
.FirstOrDefault();
if (impersonation != null)
{
impersonation.EndTime = DateTime.Now;
dc.SubmitChanges();
}
}
}
}
꽤 괜찮은 멋진 솔루션이지만, 새로운 멤버십 공급자를 작성하는 실제 해결책에 대한 해결책이 아닌지 궁금합니다. 어떻게 생각해? –
@EranBetzalel 여전히 인증을 위해 멤버 자격 공급자를 사용할 수 있습니다. 필자의 경우에는 싱글 사인온 (single sign-on)을 처리하기 위해 외부 인증 소스 (CAS)와 함께 사용됩니다. 로그인 된 사용자 대 운영자를 결정하는 데 사용됩니다. 또한 누가 보안을 위해 누가 가장하고 있는지 기록합니다. 기본 뷰 모델이 운영 사용자 (실제 사용자는 여전히 컨텍스트에서 발견됨)로 채워지는 비트를 생략했습니다. 이 기능의 한 가지 장점은 암호를 공유 할 필요가 없다는 것입니다. 지원 담당자는 다른 사람이 될 권리가 있습니다. – tvanfosson
또한 MembershipProvider에는이를 지원하는 올바른 서명이 없다는 점에 유의하십시오. 여러분이 반환하는 사용자 객체는 IPrincipal 또는 IIdentity보다 훨씬 풍부한 엔티티 모델이라는 것을 알 수 있습니다. – tvanfosson