Liferay Portal学习<五>
登录表单的定义:登录的表单可能不仅仅限于用户名和密码,还可能附带别的一些验证信息,比如图形验证码,机器相关的识别码等.那么如果要附带这样信息,在CAS中如何实现.
下面将实现登录表单中增加图形验证码验证,机器码验证功能
表单Bean实现,实现org.jasig.cas.authentication.principal.Credentials接口,代码如下:
package
com.soho.sso.caslogin;
import org.jasig.cas.authentication.principal.Credentials;
public class CasCredentials implements Credentials {
private String jpegcode;
private String username;
private String password;
private String cpucode;
public String getCpucode() {
return cpucode;
}
public void setCpucode(String cpucode) {
this.cpucode = cpucode;
}
public final String getPassword() {
return this.password;
}
public final void setPassword(final String password) {
this.password = password;
}
public final String getUsername() {
return this.username;
}
public final void setUsername(final String userName) {
this.username = userName;
}
public String toString() {
return this.username;
}
public String getJpegcode() {
return jpegcode;
}
public void setJpegcode(String jpegcode) {
this.jpegcode = jpegcode;
}
public boolean equals(final Object obj) {
if (obj == null || !obj.getClass().equals(this.getClass())) {
return false;
}
final CasCredentials c = (CasCredentials) obj;
return this.jpegcode.equals(c.getJpegcode()) && this.username.equals(c.getUsername())
&& this.password.equals(c.getPassword());
}
public int hashCode() {
return this.jpegcode.hashCode() ^ this.username.hashCode() ^ this.password.hashCode();
}
}
import org.jasig.cas.authentication.principal.Credentials;
public class CasCredentials implements Credentials {
private String jpegcode;
private String username;
private String password;
private String cpucode;
public String getCpucode() {
return cpucode;
}
public void setCpucode(String cpucode) {
this.cpucode = cpucode;
}
public final String getPassword() {
return this.password;
}
public final void setPassword(final String password) {
this.password = password;
}
public final String getUsername() {
return this.username;
}
public final void setUsername(final String userName) {
this.username = userName;
}
public String toString() {
return this.username;
}
public String getJpegcode() {
return jpegcode;
}
public void setJpegcode(String jpegcode) {
this.jpegcode = jpegcode;
}
public boolean equals(final Object obj) {
if (obj == null || !obj.getClass().equals(this.getClass())) {
return false;
}
final CasCredentials c = (CasCredentials) obj;
return this.jpegcode.equals(c.getJpegcode()) && this.username.equals(c.getUsername())
&& this.password.equals(c.getPassword());
}
public int hashCode() {
return this.jpegcode.hashCode() ^ this.username.hashCode() ^ this.password.hashCode();
}
}
表单验证类型,实现org.springframework.validation.Validator 接口:
package
com.soho.sso.caslogin;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
public class CasCredentialsValidator implements Validator {
public boolean supports(Class arg0) {
//对于表单Bean兼容的验证
return CasCredentials.class.isAssignableFrom(arg0);
}
public void validate(Object arg0, Errors errors) {
//对于表单元素的验证
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "username",
"required.username", null);
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password",
"required.password", null);
}
}
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
public class CasCredentialsValidator implements Validator {
public boolean supports(Class arg0) {
//对于表单Bean兼容的验证
return CasCredentials.class.isAssignableFrom(arg0);
}
public void validate(Object arg0, Errors errors) {
//对于表单元素的验证
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "username",
"required.username", null);
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password",
"required.password", null);
}
}
CAS 配置文件中\WEB-INF\cas-servlet.xml的定义BeanId处 authenticationViaFormAction变更上述实现类
<
bean
id
="authenticationViaFormAction"
class ="org.jasig.cas.web.flow.AuthenticationViaFormAction" >
< property name ="centralAuthenticationService" ref ="centralAuthenticationService" />
< property name ="warnCookieGenerator" ref ="warnCookieGenerator" />
< property name ="ticketGrantingTicketCookieGenerator" ref ="ticketGrantingTicketCookieGenerator" />
< property name ="formObjectName" value ="credentials" />
< property name ="formObjectClass" value ="com.soho.sso.caslogin.CasCredentials" />
< property name ="validator" >
< bean
class ="com.soho.sso.caslogin.CasCredentialsValidator" />
</ property >
</ bean >
class ="org.jasig.cas.web.flow.AuthenticationViaFormAction" >
< property name ="centralAuthenticationService" ref ="centralAuthenticationService" />
< property name ="warnCookieGenerator" ref ="warnCookieGenerator" />
< property name ="ticketGrantingTicketCookieGenerator" ref ="ticketGrantingTicketCookieGenerator" />
< property name ="formObjectName" value ="credentials" />
< property name ="formObjectClass" value ="com.soho.sso.caslogin.CasCredentials" />
< property name ="validator" >
< bean
class ="com.soho.sso.caslogin.CasCredentialsValidator" />
</ property >
</ bean >
上述的配置定义了CAS登录验证的自定义表单的实现.但是仍然没有对这些提交的表单数据实现验证逻辑.
CAS 登录验证工作流
CAS 3.1使用了spring的webflow来实现登录验证的步骤,那么就可以在webflow插入需要验证的环节!!!
验证码的验证Action,继承自 org.springframework.webflow.action.AbstractAction
package
com.soho.sso.caslogin;
import org.springframework.webflow.Event;
import org.springframework.webflow.RequestContext;
import org.springframework.webflow.action.AbstractAction;
public class CaptchaValidateAction extends AbstractAction {
@Override
protected Event doExecute(RequestContext context) throws Exception {
System.out.println("图形验证!");
String jpegcode = (String)context.getRequestParameters().get("jpegcode");
if(jpegcode.equals(context.getExternalContext().getSessionMap().get("JPEGCODE"))){
context.getExternalContext().getRequestMap().put("JPEGCODE_MSG", "");
return this.success();
}
context.getExternalContext().getRequestMap().put("JPEGCODE_MSG", "验证码错误!");
return this.error(new Exception("验证码错误!"));
}
}
import org.springframework.webflow.Event;
import org.springframework.webflow.RequestContext;
import org.springframework.webflow.action.AbstractAction;
public class CaptchaValidateAction extends AbstractAction {
@Override
protected Event doExecute(RequestContext context) throws Exception {
System.out.println("图形验证!");
String jpegcode = (String)context.getRequestParameters().get("jpegcode");
if(jpegcode.equals(context.getExternalContext().getSessionMap().get("JPEGCODE"))){
context.getExternalContext().getRequestMap().put("JPEGCODE_MSG", "");
return this.success();
}
context.getExternalContext().getRequestMap().put("JPEGCODE_MSG", "验证码错误!");
return this.error(new Exception("验证码错误!"));
}
}
机器码的验证Action:
package
com.soho.sso.caslogin;
import org.springframework.webflow.Event;
import org.springframework.webflow.RequestContext;
import org.springframework.webflow.action.AbstractAction;
public class MacValidateAction extends AbstractAction {
private CASDao casdao;
public CASDao getCasdao() {
return casdao;
}
public void setCasdao(CASDao casdao) {
this.casdao = casdao;
}
@Override
protected Event doExecute(RequestContext context) throws Exception {
System.out.println("机器码验证!");
String macAddr = (String)context.getRequestParameters().get("macAddr");
if(macAddr==null || macAddr.trim().equals("")){
context.getExternalContext().getRequestMap().put("MACADDR_MSG", "机器验证码不能为空!");
return this.error(new Exception("机器码验证!"));
}
if(casdao.validateMacAddr(macAddr)) {
return this.success();
}
context.getExternalContext().getRequestMap().put("MACADDR_MSG", "机器码验证未通过!请检查机器码是否授权能访问系统?[" + macAddr + "]");
return this.error(new Exception("机器码验证!"));
}
}
import org.springframework.webflow.Event;
import org.springframework.webflow.RequestContext;
import org.springframework.webflow.action.AbstractAction;
public class MacValidateAction extends AbstractAction {
private CASDao casdao;
public CASDao getCasdao() {
return casdao;
}
public void setCasdao(CASDao casdao) {
this.casdao = casdao;
}
@Override
protected Event doExecute(RequestContext context) throws Exception {
System.out.println("机器码验证!");
String macAddr = (String)context.getRequestParameters().get("macAddr");
if(macAddr==null || macAddr.trim().equals("")){
context.getExternalContext().getRequestMap().put("MACADDR_MSG", "机器验证码不能为空!");
return this.error(new Exception("机器码验证!"));
}
if(casdao.validateMacAddr(macAddr)) {
return this.success();
}
context.getExternalContext().getRequestMap().put("MACADDR_MSG", "机器码验证未通过!请检查机器码是否授权能访问系统?[" + macAddr + "]");
return this.error(new Exception("机器码验证!"));
}
}
用户登陆初始化Action:
package
com.soho.sso.caslogin;
import org.springframework.webflow.Event;
import org.springframework.webflow.RequestContext;
import org.springframework.webflow.action.AbstractAction;
public class casInitUserInfoAction extends AbstractAction {
@Override
protected Event doExecute(RequestContext context) throws Exception {
System.out.println("用户初始化!");
context.getExternalContext().getSessionMap().put("USERCODE",(String)context.getRequestParameters().get("username"));
return this.success();
}
}
import org.springframework.webflow.Event;
import org.springframework.webflow.RequestContext;
import org.springframework.webflow.action.AbstractAction;
public class casInitUserInfoAction extends AbstractAction {
@Override
protected Event doExecute(RequestContext context) throws Exception {
System.out.println("用户初始化!");
context.getExternalContext().getSessionMap().put("USERCODE",(String)context.getRequestParameters().get("username"));
return this.success();
}
}
数据库操作支持:CASDao
package
com.soho.sso.caslogin;
import java.util.List;
import java.util.Map;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import com.lbxdrugs.sso.util.UtilMD5;
public class CASDao extends JdbcDaoSupport {
public Map getUser(String usercode,String pwd) throws Exception{
if(usercode==null || pwd==null || usercode.trim().equals("") || pwd.trim().equals("")){
throw new Exception("用户名或密码为空!");
}
String md5pass = UtilMD5.Crypt(pwd).toUpperCase();
Map user = this.getJdbcTemplate().queryForMap("SELECT * FROM T_CAS_USER WHERE USERCODE=?", new String[]{usercode});
if(user==null || !user.get("PASSWORD").toString().toUpperCase().equals(md5pass)){
throw new Exception("用户名或密码错误!");
}
return user;
}
public List queryUserAppList(Long userid){
List list = null;
try{
list = this.getJdbcTemplate().queryForList("SELECT APPCODE,APPNAME,APP_HOMEPAGE,LOGON_USER,LOGON_PWD FROM T_CAS_APPUSERS T1 ,T_CAS_APP T2 WHERE T1.APPID=T2.APPID AND T1.USERID=?", new Long[]{userid});
}catch(Exception e){
e.printStackTrace();
}
return list;
}
public List queryUserAppList(String username){
List list = null;
try{
Long userid;
userid=this.getJdbcTemplate().queryForLong("select userid from t_cas_user where usercode=?",new String[]{username});
list = this.getJdbcTemplate().queryForList("SELECT ROWNUM NUM,APPNAME,LOGON_USER,LOGON_PWD,APP_HOMEPAGE FROM T_CAS_APPUSERS T1, T_CAS_APP T2 WHERE T1.APPID(+) = T2.APPID AND T1.USERID(+)=?", new Long[]{userid});
}catch(Exception e){
e.printStackTrace();
}
return list;
}
public boolean validateMacAddr(String mac){
Integer ct = this.getJdbcTemplate().queryForInt("select count(*) CT from t_license where trim(upper(CODE))=? and CHECKED=1", new String[]{mac.toUpperCase()});
if(ct!=null && ct.intValue() == 1){
return true;
}
return false;
}
}
import java.util.List;
import java.util.Map;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import com.lbxdrugs.sso.util.UtilMD5;
public class CASDao extends JdbcDaoSupport {
public Map getUser(String usercode,String pwd) throws Exception{
if(usercode==null || pwd==null || usercode.trim().equals("") || pwd.trim().equals("")){
throw new Exception("用户名或密码为空!");
}
String md5pass = UtilMD5.Crypt(pwd).toUpperCase();
Map user = this.getJdbcTemplate().queryForMap("SELECT * FROM T_CAS_USER WHERE USERCODE=?", new String[]{usercode});
if(user==null || !user.get("PASSWORD").toString().toUpperCase().equals(md5pass)){
throw new Exception("用户名或密码错误!");
}
return user;
}
public List queryUserAppList(Long userid){
List list = null;
try{
list = this.getJdbcTemplate().queryForList("SELECT APPCODE,APPNAME,APP_HOMEPAGE,LOGON_USER,LOGON_PWD FROM T_CAS_APPUSERS T1 ,T_CAS_APP T2 WHERE T1.APPID=T2.APPID AND T1.USERID=?", new Long[]{userid});
}catch(Exception e){
e.printStackTrace();
}
return list;
}
public List queryUserAppList(String username){
List list = null;
try{
Long userid;
userid=this.getJdbcTemplate().queryForLong("select userid from t_cas_user where usercode=?",new String[]{username});
list = this.getJdbcTemplate().queryForList("SELECT ROWNUM NUM,APPNAME,LOGON_USER,LOGON_PWD,APP_HOMEPAGE FROM T_CAS_APPUSERS T1, T_CAS_APP T2 WHERE T1.APPID(+) = T2.APPID AND T1.USERID(+)=?", new Long[]{userid});
}catch(Exception e){
e.printStackTrace();
}
return list;
}
public boolean validateMacAddr(String mac){
Integer ct = this.getJdbcTemplate().queryForInt("select count(*) CT from t_license where trim(upper(CODE))=? and CHECKED=1", new String[]{mac.toUpperCase()});
if(ct!=null && ct.intValue() == 1){
return true;
}
return false;
}
}
Spring对象配置:\WEB-INF\cas-servlet.xml 增加上述类的定义
<!--
登录处理流增加的3个Action
-->
<!-- 图形认证码认证 -->
< bean id ="captchaValidateAction" class ="com.soho.sso.caslogin.CaptchaValidateAction" />
<!-- MAC地址认证 -->
< bean id ="macValidateAction" class ="com.soho.sso.caslogin.MacValidateAction" >
< property name ="casdao" ref ="casdao" />
</ bean >
<!-- 用户初始化 -->
< bean id ="casInitUserInfoAction" class ="com.soho.sso.caslogin.casInitUserInfoAction" />
<!-- 图形认证码认证 -->
< bean id ="captchaValidateAction" class ="com.soho.sso.caslogin.CaptchaValidateAction" />
<!-- MAC地址认证 -->
< bean id ="macValidateAction" class ="com.soho.sso.caslogin.MacValidateAction" >
< property name ="casdao" ref ="casdao" />
</ bean >
<!-- 用户初始化 -->
< bean id ="casInitUserInfoAction" class ="com.soho.sso.caslogin.casInitUserInfoAction" />
数据库操作的DAO定义WEB-INF\applicationContext.xml
<
bean
id
="casdao"
class
="com.soho.sso.caslogin.CASDao"
>
< property name ="dataSource" ref ="dataSource" />
</ bean >
< bean id ="dataSource" class ="org.springframework.jndi.JndiObjectFactoryBean" >
< property name ="jndiName" >
< value > jdbc/ds </ value >
</ property >
</ bean >
< property name ="dataSource" ref ="dataSource" />
</ bean >
< bean id ="dataSource" class ="org.springframework.jndi.JndiObjectFactoryBean" >
< property name ="jndiName" >
< value > jdbc/ds </ value >
</ property >
</ bean >
重要的一步,登录webflow的定义:WEB-INF\login-webflow.xml
<
view-state
id
="viewLoginForm"
view
="casLoginView"
>
< transition on ="submit" to ="captchaValidate" /> <!-- 转移图形验证处理 -->
</ view-state >
<!-- 图形验证 -->
< action-state id ="captchaValidate" >
< action bean ="captchaValidateAction" />
< transition on ="success" to ="macValidate" /> <!-- 机器码验证处理 -->
< transition on ="error" to ="viewLoginForm" />
</ action-state >
<!-- 机器码验证 -->
< action-state id ="macValidate" >
< action bean ="macValidateAction" />
< transition on ="success" to ="bindAndValidate" />
< transition on ="error" to ="viewLoginForm" />
</ action-state >
< action-state id ="bindAndValidate" >
< action bean ="authenticationViaFormAction" />
< transition on ="success" to ="submit" />
< transition on ="error" to ="viewLoginForm" />
</ action-state >
< action-state id ="submit" >
< action bean ="authenticationViaFormAction" method ="submit" />
< transition on ="warn" to ="warn" />
< transition on ="success" to ="casInitUserInfo" /> <!-- 插入初始化处理 -->
< transition on ="error" to ="viewLoginForm" />
</ action-state >
<!-- 初始化用户信息 -->
< action-state id ="casInitUserInfo" >
< action bean ="casInitUserInfoAction" />
< transition on ="success" to ="sendTicketGrantingTicket" />
</ action-state >
< transition on ="submit" to ="captchaValidate" /> <!-- 转移图形验证处理 -->
</ view-state >
<!-- 图形验证 -->
< action-state id ="captchaValidate" >
< action bean ="captchaValidateAction" />
< transition on ="success" to ="macValidate" /> <!-- 机器码验证处理 -->
< transition on ="error" to ="viewLoginForm" />
</ action-state >
<!-- 机器码验证 -->
< action-state id ="macValidate" >
< action bean ="macValidateAction" />
< transition on ="success" to ="bindAndValidate" />
< transition on ="error" to ="viewLoginForm" />
</ action-state >
< action-state id ="bindAndValidate" >
< action bean ="authenticationViaFormAction" />
< transition on ="success" to ="submit" />
< transition on ="error" to ="viewLoginForm" />
</ action-state >
< action-state id ="submit" >
< action bean ="authenticationViaFormAction" method ="submit" />
< transition on ="warn" to ="warn" />
< transition on ="success" to ="casInitUserInfo" /> <!-- 插入初始化处理 -->
< transition on ="error" to ="viewLoginForm" />
</ action-state >
<!-- 初始化用户信息 -->
< action-state id ="casInitUserInfo" >
< action bean ="casInitUserInfoAction" />
< transition on ="success" to ="sendTicketGrantingTicket" />
</ action-state >