ABP集成WIF實現單點登錄


ABP集成WIF實現單點登錄

參考

ojlovecd寫了三篇關於WIF文章。

使用WIF實現單點登錄Part III —— 正式實戰 

使用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>
View Code

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);
        }

服務端登錄的用戶信息。

登出只對當前機器 當前使用的瀏覽器生效。實質是瀏覽器對已訪問的子站點遍歷wsignoutcleanup1.0。
<img src="@(address)?wa=wsignoutcleanup1.0" style="display:none;" />

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM