我有以下ntier app:MVC>服务>存储库>域。我正在使用Forms身份验证。在我的MVC层之外使用Thread.CurrentPrincipal来获取我的应用程序的当前登录用户或者我应该使用HttpContext.Current.User吗?
我问的原因是Thread.CurrentPrincipal似乎存在一些问题,但我谨慎地在我的MVC层之外添加对System.Web的引用,以防我将来需要提供非Web字体结尾
更新
我一直在遵循目前收到的建议,将用户名传递给服务,作为被调用方法的参数的一部分,这导致了我原始问题的改进。我需要能够检查用户是否在我的许多Service和Domain方法中担任特定角色。似乎有几个解决方案,只是想知道哪种方法是最好的方法:
你怎么建议我继续?
答案 0 :(得分:2)
我也不会这样做,HttpContext.Current.User
特定于您的网络图层。
为什么不将用户名注入服务层?
答案 1 :(得分:2)
您应该抽象您的用户信息,使其不依赖于Thread.CurrentPrincipal
或HttpContext.Current.User
。
您可以添加一个接受用户名的构造函数或方法参数,例如。
以下是构造函数参数的过度简化示例:
class YourBusinessClass
{
string _userName;
public YourBusinessClass(string userName)
{
_userName = userName;
}
public void SomeBusinessMethodThatNeedsUserName()
{
if (_userName == "sally")
{
// do something for sally
}
}
}
答案 2 :(得分:2)
将相关用户详细信息映射到新Class
以表示LoggedInUser,并将其作为参数传递给您的业务层方法
public class LoggedInUser
{
public string UserName { set;get;}
//other relevant proerties
}
现在设置它的值并传递给BL方法
var usr=new LoggedInUser();
usr.UserName="test value "; //Read from the FormsAuthentication stuff and Set
var result=YourBusinessLayerClass.SomeOperation(usr);
答案 3 :(得分:2)
我更喜欢选项号2(在Web层之外使用Thread.CurrentPrincipal)。因为这不会对您的服务等级和数据层方法。奖金:您可以在自定义主体中存储您的角色+附加信息;
确保服务和数据层中的Thread.CurrentPrincipal与您的Web层相同;您可以在Global.asax(Application_AuthenticateRequest)中设置HttpContext.Current.User(Context.User)。您可以设置此位置的其他替代位置添加在底部。
示例代码:
//sample synchronizing HttpContext.Current.User with Thread.CurrentPrincipal
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
//make sure principal is not set for anonymous user/unauthenticated request
if (authCookie != null && Request.IsAuthenticated)
{
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
//your additional info stored in cookies: multiple roles, privileges, etc
string userData = authTicket.UserData;
CustomPrincipal userPrincipal = PrincipalHelper.CreatePrincipal(authTicket.Name, authTicket.UserData, Request.IsAuthenticated);
Context.User = userPrincipal;
}
}
当然,首先您必须实施登录表单以创建包含自定义委托人的授权Cookie。
将对服务器的任何请求(css文件,javascript文件,图像文件等)执行Application_AuthenticateRequest。要仅将此功能限制为控制器操作,您可以尝试在ActionFilter中设置自定义主体(我没有尝试过)。我试过的是在Interceptor for Controllers中设置这个功能(我使用Castle Windsor进行依赖注入和面向方面编程)。
答案 4 :(得分:1)
我相信您遇到了这个问题,因为您需要进一步限制您的域名责任。处理授权不应由您的服务或文档负责。该责任应由您的MVC层处理,因为当前用户已登录到您的网络应用程序,而不是您的域。
如果您不是尝试从服务或文档中查找当前用户,而是在MVC应用程序中执行检查,则会得到以下内容:
if(Roles.IsUserInRole("DocumentEditorRole")){
//UpdateDocument does NOT authorize the user. It does only 1 thing, update the document.
myDocumentService.UpdateDocument(currentUsername, documentToEdit);
} else {
lblPermissionDenied.InnerText = @"You do not have permission
to edit this document.";
}
干净,易于阅读,并允许您保持您的服务和域类免受授权问题。您仍然可以将Roles.IsUserInRole("DocumentEditorRole")
映射到您的viewmodel,因此您唯一丢失的是Document类中的CurrentUserCanEdit方法。但是,如果您认为您的域模型代表真实世界对象,那么该方法无论如何都不属于Document。您可能会将其视为域用户对象(user.CanEditDocument(doc)
)上的一种方法,但总而言之,如果您将授权保留在域层之外,我认为您会更高兴。