使用Windows身份验证管理mvc 5中的角色的最佳方法

时间:2015-07-20 14:14:01

标签: c# asp.net-mvc-5 entity-framework-6

我正在构建基于Intranet的应用程序,如下所示,需要有关管理用户角色的最佳方法的建议。

  1. MVC 5 Windows身份验证内联网应用
  2. 无法使用AD角色需要使用该应用程序进行管理。
  3. 只有3个角色,管理员,主管,将在应用中维护的用户。
  4. 能够向角色添加/删除用户
  5. 将使用AD获取用户名称和电子邮件,然后在应用程序中保留。
  6. 我正在使用Entity framework 6和sql server(这不会改变)
  7. 我不确定是否创建自己的自定义方法来管理角色,而不是使用asp.net标识方法或任何其他方法。

    我在想,因为它是一个相对简单的应用程序,我可能只使用自己的方法?

1 个答案:

答案 0 :(得分:1)

嗯,

它的工作,但如果是我,我会使用Windows Identity Foundation(WIF 4.5)。我将创建一个自定义安全令牌服务和安全令牌配置类。

首先:

在EF中构建两个名为Roles和UsersInRoles的表。

角色

  1. RoleId(自动增量)
  2. 角色(varchar(255))
  3. 角色中的用户

    1. UserName(varchar(255),Unique,Primary Key)
    2. RoleId(外键角色 - > RoleId)
    3. 的Wif:

      第1步:

      创建一个单独的项目来构建登录站点,一个新的空MVC站点。配置web.config以使用NTLM进行身份验证并删除它的匿名访问。给它一个像login.mysite.com的网址。

      创建STS,STS配置和CertificateUtil:

      public class XYZSecurityTokenServiceConfiguration : SecurityTokenServiceConfiguration
      {
          static readonly object syncRoot = new object();
          static string stsKey = "XYZSecurityTokenServiceConfiguration";
      
      
          public static XYZSecurityTokenServiceConfiguration Current
          {
              get
              {
                  HttpApplicationState httpAppState = HttpContext.Current.Application;
                  XYZSecurityTokenServiceConfiguration myConfiguration = httpAppState.Get(stsKey) as XYZSecurityTokenServiceConfiguration;
                  if (myConfiguration != null)
                  {
                      return myConfiguration;
                  }
                  lock (syncRoot)
                  {
                      myConfiguration = httpAppState.Get(stsKey) as XYZSecurityTokenServiceConfiguration;
                      if (myConfiguration == null)
                      {
                          myConfiguration = new XYZSecurityTokenServiceConfiguration();
                          httpAppState.Add(stsKey, myConfiguration);
                      }
                      return myConfiguration;
                  }
              }
          }
      
          public XYZSecurityTokenServiceConfiguration() : base("XYZPassiveSTS", CertificateUtil.SigningCreds)
          {
              this.SecurityTokenService = typeof(TLCSecurityTokenService);
          }
      }
      
      
      public class XYZSecurityTokenService : SecurityTokenService
      {
          public XYZSecurityTokenService(SecurityTokenServiceConfiguration configuration)
              : base(configuration)
          {                        
          }
      
          void ValidateAppliesTo(EndpointReference appliesTo)
          {
              if (appliesTo == null)
              {
                  throw new ArgumentNullException("appliesTo");
              }
          }
      
          protected override Scope GetScope(ClaimsPrincipal principal, RequestSecurityToken request)
          {
              ValidateAppliesTo(request.AppliesTo);
      
              Scope scope = new Scope(
                  request.AppliesTo.Uri.OriginalString,
                  SecurityTokenServiceConfiguration.SigningCredentials);
              scope.TokenEncryptionRequired = false;
      
              scope.ReplyToAddress = scope.AppliesToAddress;
              //scope.ReplyToAddress = request.ReplyTo;
      
              return scope;
          }
      
          protected override ClaimsIdentity GetOutputClaimsIdentity(ClaimsPrincipal principal, RequestSecurityToken request, Scope scope)
          {
              //We Can Add Additonal Claims Here!
              ClaimsIdentity claims = new ClaimsIdentity();
              claims.AddClaims(principal.Claims);
              string userName = principal.Identity.Name;
      
              //Use EF To get user's roles by userName,
      
              var roles = DBContext.GetRolesForUser(userName);
              foreach (var role in roles)
              {
                 Claim roleClaim = new Claim(ClaimTypes.Role, role.Role, ClaimValueTypes.String);
                 claims.AddClaims(roleClaim);
              }
          }
      }
      
      public class CertificateUtil
      {
          #region Fields
          private const string SIGNING_CERTIFICATE_NAME = "CN=TokenSigningCert";
          private const string ENCRYPTING_CERTIFICATE_NAME = "CN=TokenSigningCert";
          private static SigningCredentials _signingCreds = null;
          private static EncryptingCredentials _encryptingCreds = null;
          #endregion
      
          #region Properties
          public static SigningCredentials SigningCreds
          {
              get
              {
                  if (_signingCreds == null)
                      _signingCreds = new X509SigningCredentials(CertificateUtil.GetCertificate(StoreName.TrustedPeople, StoreLocation.LocalMachine, SIGNING_CERTIFICATE_NAME));
                  return _signingCreds;
              }
          }
          public static EncryptingCredentials EncryptingCreds
          {
              get
              {
                  if (_encryptingCreds == null)
                      _encryptingCreds = new X509EncryptingCredentials(CertificateUtil.GetCertificate(StoreName.TrustedPeople, StoreLocation.LocalMachine, ENCRYPTING_CERTIFICATE_NAME));
                  return _encryptingCreds;
              }
          }
      
          #endregion
      
          /// <summary>
          /// Get the certificate from a specific store/location/subject.
          /// </summary>
          private static X509Certificate2 GetCertificate(StoreName name, StoreLocation location, string subjectName)
          {
              X509Store store = new X509Store(name, location);
              X509Certificate2Collection certificates = null;
              store.Open(OpenFlags.ReadOnly);
      
              try
              {
                  X509Certificate2 result = null;
      
                  //
                  // Every time we call store.Certificates property, a new collection will be returned.
                  //
                  certificates = store.Certificates;
      
                  for (int i = 0; i < certificates.Count; i++)
                  {
                      X509Certificate2 cert = certificates[i];
      
                      if (cert.SubjectName.Name.ToLower() == subjectName.ToLower())
                      {
                          if (result != null)
                          {
                              throw new ApplicationException(string.Format("More than one certificate was found for subject Name {0}", subjectName));
                          }
      
                          result = new X509Certificate2(cert);
                      }
                  }
      
                  if (result == null)
                  {
                      throw new ApplicationException(string.Format("No certificate was found for subject Name {0}", subjectName));
                  }
      
                  return result;
              }
              finally
              {
                  if (certificates != null)
                  {
                      for (int i = 0; i < certificates.Count; i++)
                      {
                          X509Certificate2 cert = certificates[i];
                          cert.Reset();
                      }
                  }
      
                  store.Close();
              }
          }
      }
      

      在登录网站中,您还需要一个控制器来处理登录和注销。

      现在,您将使用NTLM,因此对网站的任何请求都将进行身份验证,如果您关闭了匿名访问,他们无法使用NTLM登录该网站。

      因此,您的控制器只需要执行处理请求,

      if (!Request.IsAuthenticated)
          return RedirectToAction("SomethingBroke");
      
      CasPrincipal cp = User as CasPrincipal;
      ClaimsPrincipal p = new ClaimsPrincipal(cp.Identity);
                     FederatedPassiveSecurityTokenServiceOperations.ProcessRequest(System.Web.HttpContext.Current.Request, p, WIF.TLCSecurityTokenServiceConfiguration.Current.CreateSecurityTokenService(), System.Web.HttpContext.Current.Response);
      

      WIF由查询字符串参数驱动,不同的参数控制进程请求的作用。如果Query具有wssignin参数,则它会登录并重定向回主站点。如果它有wssignout,它会退出并重定向回来。

      现在,回到主站点,添加web.cofnig条目以依赖于wif登录站点,

      <configuration>
        <configSections>
          <section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
          <section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
        </configSections>
        <system.webServer>
          <modules>
            <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
            <add name="WSFederatedAuthenticationModule" type="System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
          </modules>
        </system.webServer>
        <system.identityModel>
          <identityConfiguration saveBootstrapContext="true">
            <issuerNameRegistry type="System.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
              <trustedIssuers>
                <!-- Use MMC and the Certificate Snapin to get the thumbprint for your certificate.  It will be different on other machines and this value might not work as is from source control.-->
                <add thumbprint="97f983a05587253b6835d1bd0062000c5d1f398d" name="TokenSigningCert" />
              </trustedIssuers>
            </issuerNameRegistry>
            <audienceUris mode="Never" />
          </identityConfiguration>
        </system.identityModel>
        <system.identityModel.services>
          <federationConfiguration identityConfigurationName="">
            <serviceCertificate>
              <certificateReference x509FindType="FindBySubjectName" findValue="TokenSigningCert" storeLocation="LocalMachine" storeName="TrustedPeople" />
            </serviceCertificate>
            <wsFederation passiveRedirectEnabled="true" issuer="http://login.example.com" realm="http://example.com" requireHttps="false" />
            <cookieHandler requireSsl="false" mode="Default">
              <chunkedCookieHandler chunkSize="2000" />
            </cookieHandler>
          </federationConfiguration>
        </system.identityModel.services>  
      </configuration>
      

      最后,在您的主站点中,您需要一个处理登录和注销的控制器。

      你用

      做到了
                      //To Log In
                  FederatedAuthentication.WSFederationAuthenticationModule.RedirectToIdentityProvider("MYSiteIDYouMakeUpHere", "TheUrlToReturnToAfterLoginHere", true);
      
                  //ToLogOut
                  var issuer = FederatedAuthentication.FederationConfiguration.WsFederationConfiguration.Issuer;
                  var signOutUrl = WSFederationAuthenticationModule.GetFederationPassiveSignOutUrl(issuer, "returnurlhere", null);
                  Redirect(signOutUrl);
      
相关问题