旧版本的CAS实现思路
核心原理(CAS 1.0 协议)
- 用户访问受保护页面
/admin/admin.aspx web.config权限配置拦截匿名用户,自动跳转登录页CasEnter.aspxCasEnter.aspx判断URL有无ticket参数
- 无ticket:重定向到CAS服务端登录地址,并传入当前站点地址
service - 携带ticket:调用
serviceValidate接口向CAS服务器校验票据
- CAS返回XML,解析出登录用户名
- 校验成功后调用
FormsAuthentication.SetAuthCookie()写入本地Forms登录票据,跳转目标页面 - 后续访问受保护目录,由ASP.NET Forms身份识别登录状态
web.config 配置
<system.web>
<authentication mode="Forms">
<!-- loginUrl指向CasEnter.aspx 作为CAS入口中转页 -->
<forms loginUrl="CasEnter.aspx"
defaultUrl="admin/admin.aspx"
name=".LoginFormsTicket"
path="/"
timeout="40"
protection="All">
</forms>
</authentication>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
<!-- 限制admin目录禁止匿名访问 -->
<location path="admin">
<system.web>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
</location>Code language: HTML, XML (xml)
新版CAS服务端默认强制HTTPS,
casUrl必须填写https://127.0.0.1:8443/cas/
<appSettings>
<!-- 新版CAS7地址,末尾带斜杠 -->
<add key="casUrl" value="https://127.0.0.1:8443/cas/"/>
</appSettings>Code language: HTML, XML (xml)
CasEnter.aspx 页面代码
1. CasEnter.aspx 前端
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="CasEnter.aspx.cs" Inherits="CasStudy.Web.CasEnter" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>CAS中转登录</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="Label1" runat="server"></asp:Label><br />
<asp:HyperLink ID="HyperLink1" runat="server">重新认证</asp:HyperLink>
</div>
</form>
</body>
</html>Code language: HTML, XML (xml)
2. CasEnter.aspx.cs 后端
接口升级为CAS3.0 p3/serviceValidate
增加HttpClient替代废弃WebClient
增加自签名证书兼容(本地测试新版CAS必备)
命名空间处理CAS返回XML命名空间
using System;
using System.Configuration;
using System.Net;
using System.Net.Http;
using System.Xml;
using System.Web.Security;
public partial class CasEnter : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string casHost = ConfigurationManager.AppSettings["casUrl"];
string ticket = Request.QueryString["ticket"];
string service = Request.Url.GetLeftPart(UriPartial.Path);
// 没有票据,跳转CAS登录页
if (string.IsNullOrEmpty(ticket))
{
string redirectUrl = $"{casHost}login?service={Uri.EscapeDataString(service)}";
Response.Redirect(redirectUrl);
return;
}
// 校验ticket
string username = ValidateTicket(casHost, ticket, service);
if (string.IsNullOrEmpty(username))
{
Label1.Text = "抱歉!CAS认证失败,请重试!";
HyperLink1.NavigateUrl = Request.Url.AbsolutePath;
}
else
{
// 写入Forms身份票据,完成本地登录
FormsAuthentication.SetAuthCookie(username, false);
// 跳转到目标页面
Response.Redirect(FormsAuthentication.DefaultUrl);
}
}
/// <summary>
/// CAS3.0 p3/serviceValidate 票据校验
/// </summary>
private string ValidateTicket(string casHost, string ticket, string service)
{
// 新版CAS推荐使用 p3/serviceValidate(CAS3.0协议)
string validateUrl = $"{casHost}p3/serviceValidate?ticket={Uri.EscapeDataString(ticket)}&service={Uri.EscapeDataString(service)}";
// 本地测试:允许不受信任SSL证书(生产环境删除这段!)
ServicePointManager.ServerCertificateValidationCallback += (s, cert, chain, err) => true;
using var httpClient = new HttpClient();
string xml = httpClient.GetStringAsync(validateUrl).Result;
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);
// CAS3返回xml命名空间
nsMgr.AddNamespace("cas", "http://www.yale.edu/tp/cas");
// 查找用户节点
XmlNode userNode = doc.SelectSingleNode("//cas:authenticationSuccess/cas:user", nsMgr);
return userNode?.InnerText;
}
}Code language: HTML, XML (xml)
Previous: 安装