在mvc 5中使用windows身份验证管理角色的最佳方法
本文关键字:角色 管理 最佳 方法 身份验证 windows mvc | 更新日期: 2023-09-27 18:03:40
我正在构建一个基于内部网的应用程序如下,需要对管理用户角色的最佳方式的建议。
- MVC 5 windows认证内网应用。
- 不能对需要在应用中管理的角色使用AD。
- 只有3个角色,管理员,主管,用户将在应用程序中维护。
- 向角色添加/删除用户的能力
- 将使用AD获取用户名和电子邮件,然后在应用程序中保存。
- 我正在使用实体框架6和sql server(这不会改变)
我不确定创建自己的自定义方法来管理角色,而不是使用asp.net身份方法或任何其他方法。
我在想,因为它是一个相对简单的应用程序,我可能只是利用我自己的方法?
嗯,
这是工作,但如果是我,我会使用Windows身份基础(WIF 4.5)。我会创建一个自定义安全令牌服务和安全令牌配置类。
:
在EF中创建两个名为Roles和UsersInRoles的表。角色- RoleId(自动递增)
- 角色(varchar (255)
Users In Roles
- 用户名(varchar(255),唯一,主键)
- RoleId(外键角色-> RoleId)
如:
步骤1:
创建一个单独的项目来构建登录站点,一个新的空MVC站点。配置web。配置使用NTLM进行身份验证,并删除其匿名访问。给它一个url,比如login.mysite.com。
创建STS、STS配置和证书:
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();
}
}
}
在Login站点中,您还需要一个控制器来处理登录和注销。
现在,您将使用NTLM,因此任何对站点的请求都将被验证,如果您关闭匿名访问,他们无法在不使用NTLM登录的情况下访问站点。
因此你的控制器只需要执行Process Request,
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由查询字符串参数驱动,不同的参数控制Process Request做什么。如果查询有wssignin参数,那么它登录并重定向回主站点。如果它有wssignout,它会退出并重定向回来。
现在,回到你的主站,添加web。将条目设置为依赖于wi登录站点
<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);