ABP集成WIF实现单点登录
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); }
服务端登录的用户信息。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?