我正在构建基于Intranet的应用程序,如下所示,需要有关管理用户角色的最佳方法的建议。
我不确定是否创建自己的自定义方法来管理角色,而不是使用asp.net标识方法或任何其他方法。
我在想,因为它是一个相对简单的应用程序,我可能只使用自己的方法?
答案 0 :(得分:1)
嗯,
它的工作,但如果是我,我会使用Windows Identity Foundation(WIF 4.5)。我将创建一个自定义安全令牌服务和安全令牌配置类。
首先:
在EF中构建两个名为Roles和UsersInRoles的表。
角色
角色中的用户
的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);