CAS 3.2虽然有中文界面,但是确是不支持中文账号和密码登录的。
CAS 3.2不支持中文帐户和密码登录体现在两个方面:
1、中文帐户和密码不能在cas登录页面正常登录。
2、中文帐户在用户登录后应用端服务请求cas服务器验证并返回用户登录帐户时,cas服务器的返回结果出现乱码。(下图中红色圈起的步骤)
下面就这两个方面分别给出解决方案。
1、中文帐户和密码不能在cas登录页面正常登录。
为了解决这个问题,需要给CAS的配置文件加一个过滤器EncodingFilter(就像传统JSP网站解决中文问题的方法一样)
<filter>
<description>EncodingFilter</description>
<filter-name>EncodingFilter</filter-name>
<filter-class>org.leoframework.web.EncodingFilter</filter-class>
<init-param>
<description>encoding_charset</description>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<description>ignore?</description>
<param-name>ignore</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
这个filter要在所有filter的最前面配置。
其中org.leoframework.web.EncodingFilter为笔者自己开发的框架LeoFramework中的一个类,其实EncodingFilter类型的实现很简单,也可以自己实现。下面是这个类的代码:
/*
* EncodingFilter.java
*/
package org.leoframework.web;
import javax.servlet.*;
import java.io.IOException;
/**
*
* @author Leo
*/
public class EncodingFilter implements Filter {
protected String encoding = null;
protected FilterConfig filterConfig = null;
protected boolean ignore = true;
public void destroy() {
this.encoding = null;
this.filterConfig = null;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
// Conditionally select and set the character encoding to be used
if (ignore || (request.getCharacterEncoding() == null)) {
String encoding = selectEncoding(request);
if (encoding != null)
request.setCharacterEncoding(encoding);
}
// Pass control on to the next filter
chain.doFilter(request, response);
}
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
this.encoding = filterConfig.getInitParameter("encoding");
String value = filterConfig.getInitParameter("ignore");
if (value == null)
this.ignore = true;
else if (value.equalsIgnoreCase("true"))
this.ignore = true;
else if (value.equalsIgnoreCase("yes"))
this.ignore = true;
else
this.ignore = false;
}
protected String selectEncoding(ServletRequest request) {
return (this.encoding);
}
}
然后要在数据库连接中显示声明数据库所用的编码,笔者用的是Mysql数据库utf8编码,所以数据库连接的声明应该为:
在cas.properties文件中的写法为:
db.url=jdbc:mysql://localhost:3306/passport_db?useUnicode=true&characterEncoding=utf-8
在deployerConfigContext.xml可以通过${db.url}来调用这个配置,如:
<property name="url" value="${db.url}" />
要是在xml文件中的<value></value>中间&要写成& 如下为示例:
<property name="url">
<value>jdbc:mysql://localhost:3306/passport_db?useUnicode=true&characterEncoding=utf-8</value>
</property>
2、中文帐户在用户登录后应用端服务请求cas服务器验证并返回用户登录帐户时,cas服务器的返回结果出现乱码。
这个问题是由cas服务返回的页面没有设置对应的编码引起的。
cas服务支持多种协议,他们有:cas1.0 cas2.0 Saml1.0 等。这些协议对应的返回验证结果页面是不同的,修改的方法也不一样。这里就cas1.0和cas2.0协议给出乱码的解决方案。(Saml1.0的解决方法和cas1.0近似)请根据你的系统所使用的协议来选择做相应的修改。
cas1.0:
cas1.0的验证结果页面是通过cas-server-3.2.1-release源码目录中的cas-server-3.2.1-release/cas-server-3.2.1/cas-server-core/src/main/java/org/jasig/cas/web/view目录下的Cas10ResponseView.java文件来定义的。
乱码解决办法:在原代码中加入以下红色部门代码
response.setContentType("text/xml;charset="+pagecharset);
if (this.successResponse) {
String userid=assertion.getChainedAuthentications().get(0).getPrincipal().getId();
response.getWriter().print("yes/n" + userid + "/n");
} else {
response.getWriter().print("no/n/n");
}
其中pagecharset为页面编码,可以换为你想要的编码(gbk或是gb2312或是utf-8)
修改完后,要重新编译cas-server-core,做法是,先安装Maven(Maven安装与配置),然后在DOS提示符下进入目录:{你的cas源码所在目录}/cas-server-3.2.1-release/cas-server-3.2.1/cas-server-core/
运行命令:mvn package install
如果你是第一次编译,这个过程会相当长,因为mvn要为cas的所有依赖库建议一个本地的repository(18m),建立repository的过程要通过网络下载很多文件。本地repository所在的位置:{用户目录}/.m2/,如在windows中这个目录就是C:/Documents and Settings/username/.m2 。
如果你不想再次编译的话,留下你的邮箱,我可以把编译好的文件发给你。
cas2.0:
cas2.0协议的验证结果页面是通过目录:cas/WEB-INF/view/jsp/protocol/2.0/ 下定义的jsp(jstlview)模板页面来定义的。
casProxySuccessView.jsp:对应验证成功的页面(这个页面还包含用户登录的帐户名)。
casServiceValidationFailure.jsp:对应验证失败页面。
乱码解决办法:
在casProxySuccessView.jsp和casServiceValidationFailure.jsp页面代码的最前面加上:<%@page pageEncoding="pagecharset"%>
其中pagecharset为页面编码,可以换为你想要的编码(gbk或是gb2312或是utf-8)
附:
我修改后的Cas10ResponseView.java:
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.ja-sig.org/products/cas/overview/license/
*/
package org.jasig.cas.web.view;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jasig.cas.validation.Assertion;
/**
* Custom View to Return the CAS 1.0 Protocol Response. Implemented as a view
* class rather than a JSP (like CAS 2.0 spec) because of the requirement of the
* line feeds to be "/n".
*
* @author Scott Battaglia
* @version $Revision: 42053 $ $Date: 2007-06-10 09:17:55 -0400 (Sun, 10 Jun 2007) $
* @since 3.0
*/
public final class Cas10ResponseView extends AbstractCasView {
/**
* Indicate whether this view will be generating the success response or
* not.
*/
private boolean successResponse;
protected void renderMergedOutputModel(final Map model,
final HttpServletRequest request, final HttpServletResponse response)
throws Exception {
final Assertion assertion = getAssertionFrom(model);
String charset=request.getParameter("charset");
if(charset==null||"".equals(charset)){
charset="utf-8";
}
response.setContentType("text/xml;charset="+charset);
if (this.successResponse) {
String userid=assertion.getChainedAuthentications().get(0).getPrincipal().getId();
response.getWriter().print("yes/n" + userid + "/n");
} else {
response.getWriter().print("no/n/n");
}
}
public void setSuccessResponse(final boolean successResponse) {
this.successResponse = successResponse;
}
public String chgCharset(String theStr, String theCharsetSrc, String theCharsetDet) {
String rtnStr=theStr;
if(theStr!=null&&theCharsetSrc!=null&&theCharsetDet!=null){
try {
rtnStr = new String(theStr.getBytes(theCharsetSrc),theCharsetDet) ;
} catch (Exception e) {
e.printStackTrace();
}
}else{
String thelog="chgCharset_Error:theCharsetSrc="+theCharsetSrc+"theCharsetDet"+theCharsetDet;
System.out.println(thelog);
}
return rtnStr;
}
}
我修改后的casProxySuccessView.jsp:
<%@page pageEncoding="UTF-8"%><%@ page session="false" %><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %><cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
<cas:authenticationSuccess>
<cas:user>${fn:escapeXml(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.id)}</cas:user>
<c:if test="${not empty pgtIou}">
<cas:proxyGrantingTicket>${pgtIou}</cas:proxyGrantingTicket>
</c:if>
<c:if test="${fn:length(assertion.chainedAuthentications) > 1}">
<cas:proxies>
<c:forEach var="proxy" items="${assertion.chainedAuthentications}" varStatus="loopStatus" begin="0" end="${fn:length(assertion.chainedAuthentications)-2}" step="1">
<cas:proxy>${fn:escapeXml(proxy.principal.id)}</cas:proxy>
</c:forEach>
</cas:proxies>
</c:if>
</cas:authenticationSuccess>
</cas:serviceResponse>
我修改后的casServiceValidationFailure.jsp:
<%@page pageEncoding="UTF-8"%><%@ page session="false" contentType="text/plain" %><%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %><cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
<cas:authenticationFailure code='${code}'>
${fn:escapeXml(description)}
</cas:authenticationFailure>
</cas:serviceResponse>
cas1.0的验证结果格式:
1、成功:"yes/n" + userid + "/n"
yes
userid
2、失败:"no/n/n"
no
caso2.0的验证结果格式:
1、成功:
<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
<cas:authenticationSuccess>
<cas:user>userid</cas:user>
</cas:authenticationSuccess>
</cas:serviceResponse>
2、失败:
<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
<cas:authenticationFailure code='INVALID_TICKET'>
未能够识别出目标 'ST-4-NdWdS3eURcC7bdjovZyI-cas'票根
</cas:authenticationFailure>
</cas:serviceResponse>
oracle数据库的driver url username password的写法:
db.driver=oracle.jdbc.driver.OracleDriver
db.url=jdbc:oracle:thin:@192.168.1.1:1521:xxxx
db.username=xxxx
db.password=xxxx