代码改变世界

单点登录(跨域)

2015-08-11 23:44  Carl Xing  阅读(837)  评论(0编辑  收藏  举报

工程目录如下图

站点Site为应用站点,SSOAuth为授权站点。

一、先看Site站点:

1、Auth目录下允许匿名用户,看Auth目录web.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.web>
    <authorization>
      <allow users="*"/>
    </authorization>
  </system.web>
</configuration>

根目录及其它目录阻止匿名访问,看根目录web.config

<configuration>
    <system.web>
      <compilation debug="true" targetFramework="4.0" />
      <authentication mode="Forms">
        <forms name=".SiteAuth" loginUrl="~/auth/login.aspx"/>
      </authentication>
      <authorization>
        <deny users="?"/>
      </authorization>
    </system.web>

</configuration>

登录地址为~/auth/login.aspx,这个页面其实是中转跳转到SSOAuth的Login.aspx。其中“http://www.ssoauth.com/login.aspx”就是认证站点的认证地址。

namespace Site.Auth
{
    public partial class Login : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!string.IsNullOrEmpty(Request.QueryString["ReturnUrl"]))
            {
                string redirectUrl = "http://www.ssoauth.com/login.aspx?returnUrl=" + HttpUtility.UrlEncode(
                    Request.Url.Scheme+"://"+Request.Url.Host+Request.QueryString["ReturnUrl"]
                    );
                Response.Redirect(redirectUrl);
            }
        }
    }
}

再看auth目录下的login.ashx,因为认证站点需跨域访问,故返回类型符合jsonp

namespace Site.Auth
{
    /// <summary>
    /// Login1 的摘要说明
    /// </summary>
    public class Login1 : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "application/json";
            string callback = context.Request.QueryString["callback"];
            if (!string.IsNullOrEmpty(context.Request.QueryString["sid"]))
            {
                //todo -- check the sid is valid
                //add forms cookie
                FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, "auth", DateTime.Now,
                    DateTime.Now.AddMinutes(1), false, "siteTicketUserData");
                HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName);
                cookie.Path = "/";
                cookie.Expires = DateTime.Now.AddSeconds(30);
                cookie.Value = FormsAuthentication.Encrypt(ticket);
                context.Response.Cookies.Add(cookie);
                string json = "{\"status\":\"success\"}";
                context.Response.Write(callback + "(" + json + ")");
            }
            else
            {
                string json = "{\"status\":\"fail\"}";
                context.Response.Write(callback + "(" + json + ")");
            }
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

二、SSOAuth站点

Login.aspx后台:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Security;

namespace SSOAuth
{
    public partial class Login : System.Web.UI.Page
    {
        /// <summary>
        /// 返回路径
        /// </summary>
        public string ReturnUrl
        {
            get
            {
                return Request.QueryString["returnUrl"];
            }
        }

        /// <summary>
        /// 站点登录地址
        /// </summary>
        public string SiteLogin
        {
            get;
            set;
        }

        /// <summary>
        /// 票据
        /// </summary>
        public string Sid
        {
            get;
            set;
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            HttpCookie cookie = Request.Cookies[FormsAuthentication.FormsCookieName];
            if (cookie == null)
            {
                loginField.Visible = true;
                return;
            }
            else
            {
                loginField.Visible = false;
                LoginSite(cookie);
            }
        }

        private void LoginSite(HttpCookie cookie)
        {
            Sid = cookie.Value;
            if (!string.IsNullOrEmpty(ReturnUrl))
            {
                SetSiteLogin();
                if (!string.IsNullOrEmpty(SiteLogin))
                {
                    divScript.Visible = true;
                }
            }
        }

        private void SetSiteLogin()
        {
            Uri hostUri = new Uri(ReturnUrl);
            string hostName = hostUri.Host;
            switch (hostName)
            {
                case "www.site1.com":
                    SiteLogin = "http://www.site1.com/auth/login.ashx";
                    break;
                case "www.site2.com":
                    SiteLogin = "http://www.site2.com/auth/login.ashx";
                    break;
                default:
                    SiteLogin = null;
                    break;
            }
        }

        protected void btnLogin_Click(object sender, EventArgs e)
        {
            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, "auth", DateTime.Now, DateTime.Now.AddMinutes(2), false, tbUserName.Text);
            HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName);
            cookie.Path = "/";
            cookie.Value = FormsAuthentication.Encrypt(ticket);
            Response.Cookies.Add(cookie);
            LoginSite(cookie);
        }
    }
}

Login.aspx前台

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Login.aspx.cs" Inherits="SSOAuth.Login" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <script type="text/javascript" src="js/jquery-1.6.4.min.js"></script>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <fieldset id="loginField" runat="server" visible="false">
                <legend>Login</legend>
                <div>
                    <label>UserName</label>
                    <asp:TextBox ID="tbUserName" runat="server"></asp:TextBox>
                </div>
                <div>
                    <asp:Button ID="btnLogin" runat="server" Text="Login" OnClick="btnLogin_Click" />
                </div>
            </fieldset>
        </div>
        <div runat="server" id="divScript" visible="false">
            <script type="text/javascript">
                $(function () {
                    $.ajax({
                        url: "<%=SiteLogin %>",
                        data: { sid: "<%=Sid%>" },
                        dataType: "jsonp",
                        jsonpCallback: "callback",
                        success: function (data) {
                            if (data.status == "success") {
                                window.location.href = "<%=ReturnUrl%>";
                            }
                        }
                    });
                })
            </script>

        </div>
    </form>
</body>
</html>

三、配置

1、将Site项目配置2个站点 “www.site1.com”和"www.site2.com".

2、将SSOAuth项目配置站点名为"www.ssoauth.com".

3、访问 www.site1.com 即跳转到SSOAuth去登录,点击登录即跳转回访问页。此时再访问www.site2.com已无须再登录。