基于ASP.NET 环境下的SSO Client包的资料:https://wiki.jasig.org/display/CASC/.Net+Cas+Client
在这个网站上可以下到编译过的dll文件,也可以下载源码进行研究和修改。
将dotnet-client-1.0-Bin.zip下载下来,解压以后,加载到自己的项目的bin中,然后,根据,dotnet-client-1.0-src.zip中的web.config.sample进行相应的参数修改,主要修改casServerLoginUrl,casServerUrlPrefix,serverName,loginUrl参数。
然后,连接本地的cas-server端,就可以成功地进行单点登录操作了。
但是,换成非本地的cas-server端进行调试的时候,出现了Authentication Failure的问题。查看DotNetCasClient.log,发现,在进行认证的时候,报了下面这个错误:
DotNetCasClient.Protocol Error: 3237 : Ticket validation error: DotNetCasClient.Validation.TicketValidationException:
CAS ticket could not be validated.
在 DotNetCasClient.Validation.TicketValidator.Cas20ServiceTicketValidator.ParseResponseFromServer(String response,
String ticket)
位置 E:/Test/DotNetCasClient/DotNetCasClient/Validation/TicketValidator/Cas20ServiceTicketValidator.cs:行号 144
在 DotNetCasClient.Validation.TicketValidator.AbstractUrlTicketValidator.Validate(String ticket)
位置 E:/Test/DotNetCasClient/DotNetCasClient/Validation/TicketValidator/AbstractUrlTicketValidator.cs:行号 167
在 DotNetCasClient.CasAuthentication.ProcessTicketValidation()
位置 E:/Test/DotNetCasClient/DotNetCasClient/CasAuthentication.cs:行号 739
后来进行调试,发现,第一次进行跳转登录页面的时候,带的那个service参数,和之后,在进行验证时带的那个service参数不匹配。之后的那个参数中出现了多个ssoUrl拼接,导致了验证失败。
经过页面调试,最终发现是在DotNetCasClient/DotNetCasClient/Utils/UrlUtil.cs文件中的ConstructServiceUrl函数,在构建ServiceUrl时,进行了多次拼接。所以在ConstructServiceUrl函数中,在拼接url时,将ssoUrl这个参数直接remove掉,这样可以保证前后两个service参数的一致性,保证验证的成功。
不过本人认为,这只是一个治标不治本的办法,只能用来一时应急。应该还有更好的办法来解决这个问题。有兴趣的同道中人,可以一起讨论下。
修改过的ConstructServiceUrl函数如下:
/// <summary>
/// Constructs a service URL using configured values in the following order:
/// 1. if not empty, the value configured for Service is used
/// - otherwise -
/// 2. the value configured for ServerName is used together with HttpRequest
/// data
/// </summary>
/// <remarks>
/// The server name is not parsed from the request for security reasons, which
/// is why the service and server name configuration parameters exist, per Jasig
/// website.
/// </remarks>
/// <returns>the service URL to use, not encoded</returns>
public static string ConstructServiceUrl(bool gateway)
{
CasAuthentication.Initialize();
HttpContext context = HttpContext.Current;
HttpRequest request = context.Request;
StringBuilder buffer = new StringBuilder();
if (!(CasAuthentication.ServerName.StartsWith("https://") || CasAuthentication.ServerName.StartsWith("http://")))
{
buffer.Append(request.IsSecureConnection ? "https://" : "http://");
}
buffer.Append(CasAuthentication.ServerName);
EnhancedUriBuilder ub = new EnhancedUriBuilder(buffer.ToString());
ub.Path = request.Url.AbsolutePath;
ub.QueryItems.Add(request.QueryString);
ub.QueryItems.Remove(CasAuthentication.TicketValidator.ArtifactParameterName);
ub.QueryItems.Remove("ssoUrl");//移除serviceurl中的ssoUrl参数
if (gateway)
{
ub.QueryItems.Set(CasAuthentication.GatewayParameterName, "true");
}
else
{
ub.QueryItems.Remove(CasAuthentication.GatewayParameterName);
}
return ub.Uri.AbsoluteUri;
}