.Net WebAPI程式整合CAS單點登入-API方式(不使用DotNetCasClient)

꧁执笔小白꧂發表於2024-04-23

以下是ashx一般處理程式的示例,且cas登入單獨放到了一個按鈕中:

1、登入按鈕(js) -

        console.log("cos登入");

        var originStr = window.location.origin;
        window.location.href = "https://cas.your.com/cas/login?service=" + originStr + "/WebUI/Admin";

2、登出按鈕(js) -

function loginOut() {
        $scope.closeAllTabs();
        var para = { "action": "logout" };  // 原來的登出介面
        $.ajax({
            url: ENV.ApiUrl + "bg_user_login.ashx",
            type: "post",
            data: para,
            dataType: "json",
            success: function (result) {
                if (result.success) {
                    $rootScope.loginflag = false;
                    window.sessionStorage["islogin"] = false;
                    window.sessionStorage["userid"] = "";
                    $rootScope.initIndex();
                    $timeout(function () {
                        if (window.sessionStorage["iscaslogin"] === "true") {  // 是cas登入的使用者 走cas登出的邏輯
                            var originStr = window.location.origin;
                            window.location.href = "https://cas.your.com/cas/logout?service=" + originStr + "/WebUI/Admin";
                        }
                        else {  // 不是的走原來的邏輯
                            $state.go("tabs.login");
                        }
                    }, 500);
                }
                else {
                    $.show_warning("提示", result.msg);
                }
            }
        })
    };

3、登入頁初始化方法的程式碼

    function init() {
        //#region CAS 第二版
        var href = window.location.href;

        // http://localhost:8098/WebUI/Admin/?ticket=ST-AS#/tabs/login
        if (href.indexOf("ticket") === -1) {
            // 原登入頁面的邏輯
        }
        else {
            console.log("cos登入後自動登入MES");

            // 取ticket
            var ticketStr = href;
            ticketStr = ticketStr.replace("#/tabs/default", "");
            ticketStr = ticketStr.replace("#/tabs/login", "");
            ticketStr = ticketStr.split("ticket=")[1];

            $scope.loading();
            
            var hostName1 = window.location.origin;

            http.isPost = false;
            http.Parameter = {
                action: "login_COS",  // CAS登入介面
                serviceHost: hostName1,
                ticket: ticketStr
            };
            
            http.url = "bg_user_login.ashx";
            return http.go().then(function (response) {
                $scope.hideloading();

                if (response.data.success) {
                    window.sessionStorage["iscaslogin"] = true;
                    window.sessionStorage["islogin"] = true;
                    window.sessionStorage["userid"] = response.data.userid;
                    $rootScope.initIndex();

                    //$state.go("tabs.default");
                    window.location.href = window.location.href.replace("?ticket="+ticketStr,"#/tabs/default");  // ?ticket=ST-AS
                } else {
                    window.sessionStorage["iscaslogin"] = false;
                    window.sessionStorage["islogin"] = false;
                    window.sessionStorage["userid"] = "";
                    alert(response.data.msg);
                }
            }, function (error) {
                window.sessionStorage["iscaslogin"] = false;
                window.sessionStorage["islogin"] = false;
                window.sessionStorage["userid"] = "";
                alert(error.data);
            })
        }
        //#endregion CAS 第二版
    }

    //init();

4、CAS登入介面 - 實現驗證CAS憑證

  #region 手搓Cos SSO
  // 獲取使用者casTicket
  string serviceStr = context.Request.Params["serviceHost"];  // casTicket
  string ticketStr = context.Request.Params["ticket"];  // casTicket
  if (string.IsNullOrEmpty(serviceStr))
  {
      context.Response.Write("{\"msg\":\"登入引數[serviceHost]丟失,請檢查網頁完整性!\",\"success\":false}");  // 改成自己的邏輯
  }
  else if (string.IsNullOrEmpty(ticketStr))
  {
      context.Response.Write("{\"msg\":\"登入引數[ticket]丟失,請檢查網頁完整性!\",\"success\":false}");  // 改成自己的邏輯
  }
  else
  {
      // https://cas.your.com/cas/serviceValidate?service=http://localhost:8098/WebUI/Admin&ticket=
      string tokenValid_Url = "https://cas.your.com/cas/serviceValidate?" +
      //"service=http://" + serviceStr + "/WebUI/Admin" +
      "service=" + serviceStr + "/WebUI/Admin" +
      "&ticket=" + ticketStr;

      // 驗證casTicket是否有效
      CasAuthorizeHelper.CasResult casResult = CasAuthorizeHelper.IsTokenValid_API(tokenValid_Url);
      if (!casResult.Success)
      {
          context.Response.Write("{\"msg\":\"" + casResult.Msg + "\",\"success\":false}");  // 改成自己的邏輯
      }
      else
      {
          // casTicket有效,儲存使用者資訊到Cookie
          string userId = casResult.Data.ToString();

          DateTime dateCookieExpires = DateTime.Now.AddDays(7);  // 預設7天

          List<Model.User> users = new BLL.User().GetUsersByUserId(userId);
          if (users.Count < 1)
          {
              // MES系統中無該使用者的資訊,請聯絡MES系統管理員進行新增!   // 改成自己的邏輯
              context.Response.Write("{\"msg\":\"MES系統中無該使用者的資訊,請聯絡MES系統管理員進行新增!\",\"success\":false}");
          }
          else if (users.Count > 1)
          {
              // MES系統中存在多個同工號使用者,請聯絡MES系統管理員處理!   // 改成自己的邏輯
              context.Response.Write("{\"msg\":\"MES系統中存在多個同工號使用者,請聯絡MES系統管理員處理!\",\"success\":false}");
          }
          else if (users[0].IsAble == 0)
          {
              context.Response.Write("{\"msg\":\"使用者已被禁用!\",\"success\":false}");  // 改成自己的邏輯
          }
          else
          {
              // 改成自己的邏輯
              FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
                 2, users[0].UserId, DateTime.Now, dateCookieExpires, false,
                 new JavaScriptSerializer().Serialize(users[0])  //序列化當前使用者物件
              );
              string encTicket = FormsAuthentication.Encrypt(ticket);
              HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
              if (dateCookieExpires != new DateTime(9999, 12, 31))    //不是預設時間才設定過期時間,否則會話cookie(先保留該邏輯)
                  cookie.Expires = dateCookieExpires;
              context.Response.Cookies.Add(cookie);

              context.Response.Write("{\"msg\":\"登入成功!\",\"userid\":\"" + users[0].UserId + "\",\"success\":true}");  // 改成自己的邏輯
          }
      }
  }
  #endregion 手搓Cos SSO

5、CasAuthorizeHelper

//using DotNetCasClient;
using System;
using System.Net.Http;

namespace Test
{
    /// <summary>
    /// Cas SSO幫助類
    /// </summary>
    public static class CasAuthorizeHelper
    {
        #region DotNetCasClient的功能
        ///// <summary>
        ///// 從Cookie獲取Cas憑證
        ///// </summary>
        ///// <returns></returns>
        //public static CasAuthenticationTicket GetCasAuthorizeTicket()
        //{
        //    CasAuthenticationTicket casTicket = null;
        //    var ticketCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];

        //    if (ticketCookie != null && !string.IsNullOrWhiteSpace(ticketCookie.Value))
        //    {
        //        var ticket = FormsAuthentication.Decrypt(ticketCookie.Value);

        //        if (ticket != null && CasAuthentication.ServiceTicketManager != null)
        //        {
        //            casTicket = CasAuthentication.ServiceTicketManager.GetTicket(ticket.UserData);
        //        }
        //    }
        //    return casTicket;
        //}

        ///// <summary>
        ///// 從Cookie獲取Cas憑證
        ///// </summary>
        ///// <param name="request"></param>
        ///// <returns></returns>
        //public static CasAuthenticationTicket GetCasAuthorizeTicket(this HttpRequestBase request)
        //{
        //    CasAuthenticationTicket casTicket = null;
        //    var ticketCookie = request.Cookies[FormsAuthentication.FormsCookieName];

        //    if (ticketCookie != null && !string.IsNullOrWhiteSpace(ticketCookie.Value))
        //    {
        //        var ticket = FormsAuthentication.Decrypt(ticketCookie.Value);
        //        if (ticket != null && CasAuthentication.ServiceTicketManager != null)
        //        {
        //            casTicket = CasAuthentication.ServiceTicketManager.GetTicket(ticket.UserData);

        //            //記錄登入使用者Ticket訊息明細資訊
        //            //LogUtil.Info("ticket:{0},獲取CAS使用者認證資訊:{1}", ticket.UserData, SerializerUtil.ToJson(casTicket));
        //        }
        //    }
        //    return casTicket;
        //}

        ///// <summary>
        ///// 驗證Cas憑證是否有效
        ///// </summary>
        ///// <param name="ticket"></param>
        ///// <returns></returns>
        //public static bool IsTokenValid(CasAuthenticationTicket ticket)
        //{
        //    if (ticket == null) return false;
        //    return CasAuthentication.ServiceTicketManager.VerifyClientTicket(ticket);
        //}

        ///// <summary>
        ///// 清理Cas憑證
        ///// </summary>
        //public static void ClearAuthCookie()
        //{
        //    CasAuthentication.ClearAuthCookie();
        //}
        #endregion DotNetCasClient的功能

        #region 手搓Cas SSO
        /// <summary>
        /// 驗證Cas憑證是否有效
        /// </summary>
        /// <param name="tokenValid_Url">驗證憑證的地址</param>
        /// <returns></returns>
        public static CasAuthorizeHelper.CasResult IsTokenValid_API(string tokenValid_Url)
        {
            CasResult casResult = new CasResult();

            try
            {
                Uri uri = new Uri(tokenValid_Url);

                HttpResponseMessage response = new HttpClient().GetAsync(uri).Result;
                if (response.IsSuccessStatusCode)  // 呼叫成功
                {
                    string content = response.Content.ReadAsStringAsync().Result;

                    // 正常:
                    ////<cas:serviceResponse xmlns:cas="1">
                    ////<cas:authenticationSuccess>
                    ////<cas:user></cas:user>
                    ////</cas:authenticationSuccess>
                    ////</cas:serviceResponse>
                    // null:
                    ////<cas:serviceResponse xmlns:cas="1">
                    ////  <cas:authenticationFailure code="INVALID_TICKET">未能夠識別出目標 'SVAS'票根</cas:authenticationFailure>
                    ////</cas:serviceResponse>
                    if (string.IsNullOrEmpty(content))
                    {
                        // 憑證驗證異常
                        casResult.Success = false;
                        casResult.Msg = string.Concat("透過API校驗Cas憑證失敗!報文為空!");
                    }

                    string[] contentLine = content.Split('\n');

                    if (contentLine.Length<3)
                    {
                        // 憑證驗證異常
                        casResult.Success = false;
                        casResult.Msg = string.Concat("透過API校驗Cas憑證失敗!報文異常!"+ content);
                    }

                    if (contentLine[1].Contains("authenticationFailure") && contentLine[1].Contains("未能夠識別出目標"))
                    {
                        // 憑證無效
                        casResult.Success = false;
                        casResult.Msg = "CAS憑證無效!請重新整理頁面重新登入!";
                    }
                    else if (contentLine[1].Contains("authenticationSuccess"))
                    {
                        // 憑證有效
                        casResult.Success = true;

                        string userNameStr = contentLine[2];
                        userNameStr = userNameStr.Replace("<cas:user>", "");
                        userNameStr = userNameStr.Replace("</cas:user>", "");
                        casResult.Data = userNameStr.Trim();
                    }
                    else
                    {
                        // 憑證驗證異常
                        casResult.Success = false;
                        casResult.Msg = string.Concat("透過API校驗Cas憑證失敗!報文異常!" + content);
                    }
                }
                else
                {
                    casResult.Success = false;

                    string conStr = response.Content.ReadAsStringAsync()?.Result ?? string.Empty;

                    casResult.Msg = string.Concat("透過API校驗Cas憑證失敗![", response.StatusCode.ToString(), "]", conStr);
                }
            }
            catch (Exception ex)
            {
                //Debug.WriteLine(@"\tERROR {0}", ex.Message);

                casResult.Success = false;
                casResult.Msg = "透過API校驗Cas憑證失敗!" + ex.Message;
            }

            return casResult;
        }

        /// <summary>
        /// Cas用方法結果類
        /// </summary>
        public class CasResult
        {
            public bool Success { get; set; }

            public string Msg { get; set; } = string.Empty;

            public object Data { get; set; }

            public object Obj1 { get; set; }
        }
        #endregion 手搓Cas
    }
}

相關文章