ABP集成WIF實現單點登錄
參考
ojlovecd寫了三篇關於WIF文章。
使用WIF的一些開源示例。
https://github.com/obhita/PROCenter/tree/master/ProCenter.LocalSTS/STS
https://github.com/primaryobjects/SingleSignOn
https://github.com/shinpou/Windows-Identity-Foundation-Tutorial/tree/master/Learning%20SSO
WSFederation and SAML library for Java based web applications
https://github.com/auth10/auth10-java
WIF配置過程中的一些問題
1、WIF授權
MVC項目中使用[Authorize]
,注解方式鑒權。
webform項目中使用配置文件方式鑒權。

<system.web> <authorization> <deny users="?" /> </authorization> </system.web>
2、密鑰集合不存在
Exception: System.Security.Cryptography.CryptographicException
Message: 密鑰集不存在。
解決方法:
C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys這個目錄授權的時候出錯了,一直報這個錯誤
“將安全信息應用到以下對象時發生錯誤 拒絕訪問”,為ereryone用戶分配完全控制權限,密鑰集的錯誤就解決了。
3、部署時,出現
用戶代碼未處理 System.Security.Cryptography.CryptographicException 錯誤解決方法
解決方法:
IIS 應用程序池--選中你網站的所配置的應用程序池--右鍵 選擇 “高級配置” --將“加載用戶配置文件” 設置為True 。
4、thumbprint值
配置文件中<add thumbprint="xxxxxxxxxx" name="sts" />的值,使用IIS服務器證書中的指紋值。復制粘貼會帶一些特殊字符,還是手敲吧!
在ABP中集成
User.Identity && User.Identity.IsAuthenticated並不依賴Session。
Web.config文件設置或者瀏覽器請求時候刪除ASP.NET_SessionId只要保留.AspNet.ApplicationCookie存在請求身份一樣能通過驗證。
<system.web>
<sessionState mode="Off" />
</system.web>
RP站
RP OnAuthentication鑒權:
protected override void OnAuthentication(AuthenticationContext filterContext) { if (filterContext.HttpContext == null) throw new ArgumentNullException("httpContext"); IPrincipal user = filterContext.HttpContext.User; bool isFederation = false; bool isApp = false; IEnumerable<ClaimsIdentity> cl = ((ClaimsPrincipal)User).Identities; if (cl != null && cl.Count() > 0) { foreach (var item in cl) { if (item.AuthenticationType.Equals("Federation") && item.IsAuthenticated) { isFederation = true; } else if (item.AuthenticationType.Equals("ApplicationCookie") && item.IsAuthenticated) { isApp = true; if (item.Claims.Where(p => p.Type == "SSO-Login").Count() == 0) isFederation = true; } } } if (!isFederation || !isApp) filterContext.Result = new RedirectResult("/Account/Login"); if (!user.Identity.IsAuthenticated || !AbpSession.UserId.HasValue) filterContext.Result = new RedirectResult("/Account/Login"); }
RP登錄:
public async Task<ActionResult> Login(string userNameOrEmailAddress = "", string returnUrl = "", string successMessage = "") { bool isFederation = false, isApp = false; var identities = ((ClaimsPrincipal)User).Identities; if(identities!=null && identities.Count() > 0) { var federation = identities.Where(p => p.AuthenticationType == "Federation").FirstOrDefault(); if (federation != null) isFederation = federation.IsAuthenticated; var applicationCookie = identities.Where(p => p.AuthenticationType == "ApplicationCookie").FirstOrDefault(); if (applicationCookie != null) isApp = applicationCookie.IsAuthenticated; } if (!isFederation) { FederatedAuthentication.WSFederationAuthenticationModule.SignIn(null); return null; } //創建本地abpsession if (!isApp) { string name = string.Empty, role = string.Empty; ClaimsIdentity claims = User.Identity as ClaimsIdentity; if (claims != null) { var list = claims.Claims.ToList(); if (list != null && list.Count > 0) { var cName = claims.Claims.Where(p => p.Type == ClaimTypes.Name).FirstOrDefault(); if (cName != null) name = cName.Value; var cRole = claims.Claims.Where(p => p.Type == ClaimTypes.Role).FirstOrDefault(); if (cRole != null) role = cRole.Value; var cEmail = claims.Claims.Where(p => p.Type == ClaimTypes.Email).FirstOrDefault(); if (cEmail != null) name = cEmail.Value; if (name.Contains("\\")) name = name.Replace("\\", ""); if (string.IsNullOrEmpty(role)) role = ConfigHelper.GetAppSetting("UserRole"); } } var user = _userIdentity.GetUserByName(name); if (user == null) { CreateOrUpdateUserInput input = new CreateOrUpdateUserInput(); input.User = new UserEditDto(); input.User.Name = name; input.User.Surname = input.User.Name; input.User.UserName = input.User.Name; input.User.Password = Infrastructure.Authorization.Users.User.CreateRandomPassword(); input.User.EmailAddress = name + "@xx.com"; input.AssignedRoleNames = new string[] { role }; user = await _userIdentity.CreateUserAsync(input); } await SignInAsync(user); } return RedirectToAction("Index", "Home"); }
RP 登出:
public ActionResult Logout() { IEnumerable<ClaimsIdentity> cis = ((ClaimsPrincipal)User).Identities; if (cis != null && cis.Count() > 0) { foreach (var item in cis) { if (item.AuthenticationType.Equals("Federation")) { var authModule = FederatedAuthentication.WSFederationAuthenticationModule; WSFederationAuthenticationModule.FederatedSignOut(new Uri(authModule.Issuer + "/Account/Logout"), new Uri(authModule.Reply)); } else if (item.AuthenticationType.Equals("ApplicationCookie")) { _authenticationManager.SignOutAll(); } } } return RedirectToAction("Login"); }
STS認證成功后回調RP(host:www.test.com)會傳入如下信息
將信息.AspNet.ApplicationCookie、FedAuth、FedAuth1復制后使用其它瀏覽器寫入這三個Cookie刷新可正常驗證用戶信息。
FedAuth、FedAuth1是WIF STS給的認證信息。
如果訪問的子站點(www.test.com)沒有通過STS將認證(FedAuth、FedAuth1)信息回寫到子站點的Cookie中,此時使用其它已認證的子站點(FedAuth、FedAuth1)信息模擬到www.test.com站點是無法識別的。
WIF認證服務端:
CustomSecurityTokenService.cs
protected override ClaimsIdentity GetOutputClaimsIdentity(ClaimsPrincipal principal, RequestSecurityToken request, Scope scope) { //WIF返回Claims中信息,里面了包含自己想要的聲明 ClaimsIdentity outgoingIdentity = new ClaimsIdentity(); var claims = principal.Claims.ToList(); foreach(var item in claims) { if(item.Type != "AspNet.Identity.SecurityStamp" && item.Type != ClaimTypes.NameIdentifier) { outgoingIdentity.AddClaim(new Claim(item.Type, item.Value)); } } SingleSignOnManager.RegisterRP(scope.AppliesToAddress); return outgoingIdentity; }
將Claims信息調用RP站管道信息帶入到RP站:
[UnitOfWork] public ActionResult Index() { FederatedPassiveSecurityTokenServiceOperations.ProcessRequest( System.Web.HttpContext.Current.Request, User as ClaimsPrincipal, CustomSecurityTokenServiceConfiguration.Current.CreateSecurityTokenService(), System.Web.HttpContext.Current.Response); var loginInfo = AsyncHelper.RunSync(() => _sessionAppService.GetCurrentLoginInformations()); return View(loginInfo); }
服務端登錄的用戶信息。