내 추상 기본 컨트롤러의 사용자 (user.identity.name)와 같이 사용자가 왜 있습니까?
-
08-07-2019 - |
문제
나는 관련 질문을했지만 제목을 엉망으로 만들었고 아무도 그것을 이해하지 못했습니다. 나는 지금 더 정확하게 질문을 할 수 있기 때문에, 나는 새로운 질문으로 그것을 재구성하고 오래된 질문을 닫기로 결정했습니다. 그 죄송합니다.
그래서 내가하고 싶은 것은 데이터 (DB에 저장된 내 맞춤형 사용자의 별명)를 loginusercontrol에 전달하는 것입니다. 이 로그인은 html.renderpartial ()을 통해 마스터 페이지에서 렌더링되므로 실제로해야 할 일은 ViewData [ "usernickName"]가 모든 호출에 존재하는지 확인하는 것입니다. 하지만 모든 컨트롤러의 모든 작업에서 ViewData [ "usernickName"]를 채우고 싶지 않으므로 사용하기로 결정했습니다. 이 접근법 그리고 그렇게하는 것과 같은 추상 기본 컨트롤러를 만듭니다.
public abstract class ApplicationController : Controller
{
private IUserRepository _repUser;
public ApplicationController()
{
_repUser = RepositoryFactory.getUserRepository();
var loggedInUser = _repUser.FindById(User.Identity.Name); //Problem!
ViewData["LoggedInUser"] = loggedInUser;
}
}
이런 식으로 내 파생 컨트롤러가 무엇을 하든지 사용자 정보는 이미 존재합니다.
여태까지는 그런대로 잘됐다. 이제 문제를 위해 :
user.identity.name keak에 전화 할 수 없습니다 User
이미 null입니다. 모든 파생 컨트롤러에서는 그렇지 않으므로 추상 기본 컨트롤러에만 해당됩니다.
코드의 다른 장소에서 formsauthentication을 통해 user.identity.name을 설정하고 있지만 이것이 문제가 될 수 없다고 생각합니다 - Afaik user.identity.name은 null이지만 사용자 자체는 아닙니다.
HTTPContext를 사용할 수없는 것처럼 보입니다 (또한 NULL ;-)가 여기에서 간단하지만 중요한 지점을 놓치고 있습니다. 누구든지 힌트를 줄 수 있습니까? 정말 감사하겠습니다.
해결책
제 생각에는 컨트롤러의 기본 생성자가 사용자를 채우지 않고 컨트롤러 텍스트가 컨트롤러에 대해 설정된 경우에만 알려져있을 것입니다. MVC 응용 프로그램의 수명주기에 대한 문서에서 이것을 확인해야합니다 ( 여기 미리보기 버전이기 때문에 약간 오래된 것이지만 MVC의 소스 코드를 확인하십시오.
MVC가있는 코드 (미리보기 버전이지만 괜찮을 것입니다) : (컨트롤러에서)
public IPrincipal User {
get {
return HttpContext == null ? null : HttpContext.User;
}
}
...
public HttpContextBase HttpContext {
get {
return ControllerContext == null ? null : ControllerContext.HttpContext;
}
}
코드에서 기본 생성자의 구현이 표시되지 않습니다. 그것은 ControlLerContext가 건설 시점에 null임을 증명할 것입니다.
따라서 코드를 다른 곳에서 실행해야합니다.
다른 팁
이 문제에 대한 답은 실제로 매우 간단합니다. Raimond가 지적한 이유로 생성자 내에서 코드를 실행할 수는 없지만 생성자 외부에서 수행 할 수 있습니다.
그래서 내가 한 일은 기본 컨트롤러 클래스에서 onactionExecuting ()을 우선적으로 재정의하는 것이 었습니다 (나는 그것에 대해 사용자 정의 속성을 만들었지 만 메소드를 우선적으로 작동해야 함).
이제 예상대로 작동하며 반복 코드가 없습니다.
컨트롤러가 인스턴스화 된 후까지 사용자 속성은 할당되지 않지만 다음과 함께 생성자로부터 조기 액세스를 얻을 수 있습니다.
System.Web.HttpContext.Current.User
다음과 같은 것을 사용하여 이것을 잡을 수 있습니까?
HttpContext currentContext = HttpContext.Current;
string userName = currentContext.User.Identity.Name;
아니면 httpcontext는 항상 비어 있습니까?
추상 클래스의 생성자를 통해 httpcontext를 설정할 수 있습니까? 이런 식으로 사용 하시겠습니까?
감사합니다 Raimond. 나는 명백한 것을보기에는 너무 피곤했다. @Keeney : 예, 컨텍스트는 항상 널입니다. Raimond는 이유를 지적했습니다. 어쨌든 고마워요
현재의 작업 솔루션 (내가 원했던 것은 아니지만)은 모든 컨트롤러 동작을 장식하는 데 사용하는 속성입니다. 구현은 다음과 같습니다.
public class MasterPageDataAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
IUserRepository _repUser = RepositoryFactory.getUserRepository();
IPrincipal siteUser = filterContext.Controller.ControllerContext.HttpContext.User;
User loggedInUser = null;
if (siteUser == null || siteUser.Identity.Name == null)
{
//do nothing
}
else
{
loggedInUser = _repUser.findUserById(siteUser.Identity.Name);
}
filterContext.Controller.ViewData["LoggedInUser"] = loggedInUser ?? new User { Nickname = "Guest" };
}
}
나는 건조 원칙을 따르는 방식으로 해당 코드를 실행하는 방법을 조사 할 것입니다. 이는 속성을 사용하여 자신을 반복하는 것을 의미하기 때문입니다. 어쩌면 일종의 인터셉터 (흥미로운 아이디어) 또는 후크가 도움이 될 수 있습니다.
그것에 대한 건배.
베이스 컨트롤러 구현 에서이 작업을 수행하고 있으며 예상대로 작동합니다.
public abstract class BaseController : Controller
{
public bool LoggedOn
{
get { return User.Identity.IsAuthenticated; }
}
}
이것은 항상 나에게 진실 또는 거짓을 반환합니다 User != null
Masterfu에게 : 나는 당신의 도움과 유사한 일을했는데, 후자의 방문자를 도울 수 있기를 바랍니다. 제 경우에는 다른 사용자를위한 컨트롤러의 저장소를 만들어야하지만 컨트롤러의 생성자 (Principal) 사용자는 준비되지 않았습니다. 그래서 컨트롤러에 대한 속성을 만들었습니다.
[CreateRepositoryByUser]
public class MFCController : Controller
{
protected MFCRepository _repository
{
get { return ViewData["repository"] as MFCRepository; }
}
...
_repository는 실제로 컨트롤러의 개인 변수가 아니라 속성에 의해 생성된다.
public class CreateRepositoryByUser : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
CreateRepository(filterContext);
}
public static void CreateRepository(ActionExecutingContext filterContext)
{
if (filterContext.Controller.ViewData["repository"] == null)
{
filterContext.Controller.ViewData["repository"] =
MFCRepository.CreateMFCRepository(filterContext.Controller.ControllerContext.HttpContext.User);
}
}
}
다른 속성의 경우이 속성이 트리거되기 전에 (원금) 사용자를 사용하기를 원하는 경우 저장소를 별도로 작성하는 코드를 넣습니다.
MVC 파이프 라인에서 생성자로부터 호출이 너무 빨리 있습니다.
코드를 승인으로 이동하면 매개 변수에서 승인 된 사용자를 얻습니다. 나를 위해 일했습니다!
당신의 예에서 나는 다음과 같은 일을 할 것입니다.
public abstract class ApplicationController : Controller {
private IUserRepository _repUser;
protected override void OnAuthorization(AuthorizationContext filterContext)
{
_repUser = RepositoryFactory.getUserRepository();
var loggedInUser = _repUser.FindById(filterContext.HttpContext.User.Identity.Name); //Problem!
ViewData["LoggedInUser"] = loggedInUser;
}
}
주사 IPrincipal
필요한 경우 User
생성자에서.
// startup.cs
// Inject IPrincipal
services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);
그런 다음 AS를 추가하십시오 IPrincipal
당신의 생성자에. 보장됩니다 ClaimsPrincipal
Aspnet과 함께 - 그것이 무엇이기 때문입니다 HttpContext.User
이다.