在工作项目中使用到了单点登录,采用CAS方案,发现输入错误用户名、密码或验证码登录时没有错误提示,经过反复查询资料和尝试,找到了解决方法。
版本介绍
使用的cas版本为:
客户端:cas-client-3.2.1-release
服务器端:cas-server-3.4.10-release
具体实现
使用默认的登录页面,即cas server中的/WEB-INF/view/jsp/default/ui/casLoginView.jsp,关键代码如下:
<c:set var="contextPath" value="${pageContext.request.contextPath}"></c:set>
<form:form method="post" id="fm1" class="fm-v clearfix"
action='${contextPath}/login' commandName="${commandName}">
<form:errors path="*" id="msg" element="div" cssStyle="color:red"/><!-- 此即为页面错误提示信息所用的标签-->
……
</form:form>
首先自定义了MyCredentials,用于获取页面中提交的表单数据,如下:
package ******;
import org.jasig.cas.authentication.principal.Credentials;
public class MyCredentials implements Credentials {
private static final long serialVersionUID = 1L;
private String username;
private String password;
private String uuid;
private String code;
省略get、set方法……
然后自定义了登录验证类,如下:
public class MyAuthenticationHandler implements AuthenticationHandler {
protected final Log logger = LogFactory.getLog(getClass());
private DataSource myDataSource;//使用的数据库
public boolean authenticate(Credentials credentials)
throws AuthenticationException {
MyCredentials myCredentials = (MyCredentials) credentials;
String username = myCredentials.getUsername();
String password = myCredentials.getPassword();
String code = myCredentials.getCode();
String uuid = myCredentials.getUuid();
String codeValidateResult = validateImgCode(uuid, code);
// 验证码有问题返回页面提示。
//注意:直接抛出异常,不要用try-catch捕获
if ("301".equals(codeValidateResult)) {
// 返回登录页面信息
// "iconCodeMsg", "验证码错误"
throw new CheckCodeErrorException();
} else if ("302".equals(codeValidateResult)) {
// 返回登录页面信息
// "iconCodeMsg", "验证码已过期"
throw new CheckCodeOutofDateException();
} else if ("000".equals(codeValidateResult)) {
// 去数据库中根据账号查出对应的密码,比对是否相等
JSONObject jObject = null;
try {
jObject = new MyHttpClient().loginAuthenticate(
username, password);
} catch (Exception e) {
logger.error("验证用户名、密码时出现异常:"+e.toString());
}
if (jObject != null) {
return true;
} else {
// "用户名或密码错误";
throw new UsernamePasswordErrorException();
}
} else {
// 如果返回的是Null,则在页面上提示"系统繁忙,请稍后再试"
throw new SystemBusyErrorException();
}
}
public String validateImgCode(String uuid, String code) {
ResourceBundle res = ResourceBundle.getBundle("messages_zh_CN");
String checkcodeUrl = res.getString("checkcodevalidate.url");
String url = checkcodeUrl;
String params = "uuid=" + uuid + "&validateCode=" + code;
try {
String returnMsg = MyUtilMethods.requestHttpUrlPost(url, params);
JSONObject jb = JSONObject.fromObject(returnMsg);
return jb.getString("code");
} catch (Exception e) {
return null;
}
}
public boolean supports(Credentials credentials) {
// return false;
return true;
}
public DataSource getMyDataSource() {
return myDataSource;
}
public void setMyDataSource(DataSource myDataSource) {
this.myDataSource = myDataSource;
}
同时,需要修改/WEB-INF/deployerConfigContext.xml中的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<bean id="authenticationManager" class="org.jasig.cas.authentication.AuthenticationManagerImpl">
<property name="credentialsToPrincipalResolvers">
<list>
<!-- <bean class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver" >
<property name="attributeRepository" ref="attributeRepository" />
</bean> -->
<bean class="org.jasig.cas.myAuthentication.MyCredentialsToPrincipalResolver">
<property name="myDataSource" ref="myDataSource"></property>
</bean>
<bean class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver" />
</list>
</property>
<property name="authenticationHandlers">
<list>
<bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
p:httpClient-ref="httpClient" />
<!--自定义验证规则:-->
<bean class="org.jasig.cas.myAuthentication.MyAuthenticationHandler">
<property name="myDataSource" ref="myDataSource"/>
</bean>
</list>
</property>
</bean>
<bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
<property name="url"><value>******</value></property>
<property name="username"><value>******</value></property>
<property name="password"><value>******</value></property>
</bean>
<sec:user-service id="userDetailsService">
<sec:user name="battags" password="notused" authorities="ROLE_ADMIN" />
</sec:user-service>
<bean id="serviceRegistryDao" class="org.jasig.cas.services.InMemoryServiceRegistryDaoImpl"></bean>
<bean id="attributeRepository"
class="org.jasig.services.persondir.support.StubPersonAttributeDao">
<property name="backingMap">
<map>
<entry key="uid" value="uid" />
<entry key="eduPersonAffiliation" value="eduPersonAffiliation" />
<entry key="groupMembership" value="groupMembership" />
</map>
</property>
</bean>
</beans>
在/src/messages_zh_CN.properties中配置错误提示消息如下:
checkcode.error=\u9A8C\u8BC1\u7801\u9519\u8BEF
checkcode.outofdate.error=\u9A8C\u8BC1\u7801\u5DF2\u8FC7\u671F
usernamepassword.error=\u7528\u6237\u540D\u6216\u5BC6\u7801\u9519\u8BEF
system.busy.error=\u7CFB\u7EDF\u7E41\u5FD9\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5
最后,需要自定义异常,在异常中规定了提示的信息:
package ******;
import org.jasig.cas.authentication.handler.AuthenticationException;
public class CheckCodeErrorException extends
AuthenticationException {
private static final long serialVersionUID = 1L;
public static final CheckCodeErrorException ERROR = new CheckCodeErrorException();
/** The code description of this exception. */
private static final String CODE= "checkcode.error";
public CheckCodeErrorException(){
super(CODE);
}
public CheckCodeErrorException(final Throwable throwable) {
super(CODE,throwable);
}
public CheckCodeErrorException(final String code) {
super(code);
}
public CheckCodeErrorException(final String code,
final Throwable throwable){
super(code,throwable);
}
}
其它异常类似,只需要将 String CODE= “checkcode.error”换为在.properties中设置的相应的属性名即可。
参考文献:
http://blog.csdn.net/tch918/article/details/22075695?utm_source=tuicool&utm_medium=referral