2014-01-08 42 views
1

我正在寻找关于此问题的建议,教程和一般帮助。C#复杂登录

我目前有一个简单的登录系统,用户输入用户名/密码在数据库中验证它,然后使用[Authorize]标签设置当用户登录/注销时可以使用哪些页面。

但不是主办5个不同的系统为5个不同的客户我想合并它们。

因此,客户端可以使用用户名,密码登录,然后选择那里的公司。

我会要求公司的详细信息在每个控制器都可用,所以我可以说“为这家公司拉用户”,“为这家公司开发发票”。

我是这样做的错误方式。我只是认为一个系统会更容易支持,维护和发展。

感谢

回答

1

为了这个目的,我有AllowFor属性。它看起来像:

public class AllowFor : ActionFilterAttribute 
{ 
    private UserType userTypes = UserType.NotAuthenticated; 

    public AllowFor(UserType userTypes) 
    { 
     this.userTypes = userTypes; 
    } 

    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     if (!(filterContext.Controller is ApplicationController)) 
      throw new Exception("AllowFor attribute is acceptable only for ApplicationController"); 

     var controller = (ApplicationController)filterContext.Controller; 

     if (!userTypes.HasFlag(controller.CurrentUserType)) 
      filterContext.Result = new ViewResult 
      { 
       ViewName = "AccessRestricted" 
      }; 
     else 
      base.OnActionExecuting(filterContext); 
    } 
} 

ApplicationController只是我的类继承自Contoller。

public abstract class Application : Controller 
{ 
    public UserType CurrentUserType 
    { 
     get 
     { 
      return currentUser.UserType; 
     } 
    } 

    // singleton for current user 

    protected User __currentUser = null; 
    protected User currentUser 
    { 
     get 
     { 
      if (__currentUser == null && HttpContext != null && HttpContext.User.Identity.IsAuthenticated) 
      { 
       // access to sql based on: 
       // HttpContext.User.Identity.IsAuthenticated 
       // HttpContext.User.Identity.Name 
       // etc 
      } 
      return __currentUser; 
     } 
    } 

    // singleton for EF context 

    private MyAppContext __context = null; 
    protected MyAppContext context 
    { 
     get 
     { 
      if (__context == null) 
      { 
       __context = new MyAppContext(); 
      } 
      return __context; 
     } 
    } 
} 

实际上并不需要它,但我觉得它非常有用。只需从ApplicationContoller继承你的控制器,你就可以用单例模式检索上下文和其他对象。

属性的使用方法十分简单,只需标记你的动作与属性:

[Authorize, AllowFor(UserType.Company)] 
public ActionResult Index() 
{ 
    // ... 
} 

你可以让你AllowFor属性更加有用,它适用于类(控制器,例如),而不是动作:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, 
       AllowMultiple = false, Inherited = true)] 
public class AllowFor : ActionFilterAttribute { ... } 

如果你想获取基于表单的身份验证数据库的用户,你可以按照以下两种方法之一:

  • 通过电子邮件
  • 获取由提供商用户许可证

这是很容易通过电子邮件获取,但这种方法有几个缺点取:

  • 你必须确保你的会员资格供应商需要独特的电子邮件地址(必须设置你的会员提供的requiresUniqueEmail财产Web.configtrue

例:

<membership defaultProvider="MyMembershipProvider" userIsOnlineTimeWindow="15"> 
    <providers> 
    <clear /> 
    <add name="MyMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="MembershipConnection" applicationName="GeekJob" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="true" passwordFormat="Hashed" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="1" maxInvalidPasswordAttempts="100" passwordAttemptWindow="1440" /> 
    </providers> 
</membership> 
  • 你必须记住,[email protected][email protected]。如果您需要通过电子邮件从数据库中提取用户,则表格中必须有其他列LoweredEmail。此外,请不要忘记LoweredEmail列中的表格索引。此外,不要忘记用[StringLength(450)]属性标记它(如果您使用MS SQL Server,因为如果您在其上应用索引,字符串列不能超过450个Unicode符号)。

  • 如果用户决定更改他的电子邮件会怎么样?您需要修改成员资格和实体表。听起来像我们正在前往code smell

因此,我建议对ProviderUserKey资源相关联的会员和现有表(你还需要额外的列和索引)。

现在,您可以通过方便抓取用户:

if (HttpContext != null && HttpContext.User.Identity.IsAuthenticated) 
{ 
    MembershipUser mu = Membership.GetUser(HttpContext.User.Identity.Name); 
    return context.Users.Where(u => u.UserKey == (Guid)mu.ProviderUserKey).FirstOrDefault(); 
} 
+0

因此,我的下一个问题是,我怎么会知道用户什么工程公司? 我需要使用他的电子邮件/用户保存使用表单身份验证cookie,然后从数据库池? – LmC

+0

谢谢,我更新了帖子,看看。 –

+0

你如何使用你的应用程序:控制器?我是否继承我的所有控制器首页:应用程序? – LmC