嗯,
這是工作,但如果是我,我會使用Windows Identity Foundation(WIF 4.5)。我將創建一個自定義安全令牌服務和安全令牌配置類。
第一張:
在EF中構建兩個名爲Roles和UsersInRoles的表。
角色
- 角色ID(自動遞增)
- 作用(VARCHAR(255))
用戶在角色
- 用戶名(VARCHAR(255),唯一,主鍵)
- 角色ID(外鍵角色 - >角色ID)
的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通過查詢字符串參數驅動,不同的參數控制哪些程序請求呢。如果查詢具有wssignin參數,則它將登錄並重定向回主站點。如果它發出警告,它會註銷並重新導回。
現在回到你的主站點,添加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);
這裏有一個很好的概述。 http://www.typecastexception.com/post/2014/04/20/ASPNET-MVC-and-Identity-20-Understanding-the-Basics.aspx#The-Heart-of-it-All---ApplicationDbContext –
好的,謝謝史蒂夫我會通讀這個 – Pod