cas server的版本为cas-server-3.4.12-release
cas-servlet.xml 中
在bean handlerMappingC添加属性
<prop key="/captcha.htm">captchaImageCreateController</prop>
在文件中添加
<bean id="captchaImageCreateController" class="com.cc.flow.CaptchaImageCreateController"></bean>
替换
<bean id="authenticationViaFormAction" class="com.wokejia.flow.CustomAuthenticationViaFormAction"
p:centralAuthenticationService-ref="centralAuthenticationService"
p:warnCookieGenerator-ref="warnCookieGenerator" />
public class CustomAuthenticationViaFormAction{
private String captchaValidationParameter = "_captcha_parameter";
private String code = "code";
/**
* Binder that allows additional binding of form object beyond Spring
* defaults.
*/
private CredentialsBinder credentialsBinder;
/** Core we delegate to for handling all ticket related tasks. */
@NotNull
private CentralAuthenticationService centralAuthenticationService;
@NotNull
private CookieGenerator warnCookieGenerator;
protected Logger logger = LoggerFactory.getLogger(getClass());
public final void doBind(final RequestContext context, final Credentials credentials) throws Exception {
final HttpServletRequest request = WebUtils.getHttpServletRequest(context);
if (this.credentialsBinder != null && this.credentialsBinder.supports(credentials.getClass())) {
this.credentialsBinder.bind(request, credentials);
}
}
public final String submit(final RequestContext context, Credentials credentials, final MessageContext messageContext) throws Exception {
final HttpServletRequest request = WebUtils
.getHttpServletRequest(context);
if(credentials instanceof CustomLoginCredentials){
CustomLoginCredentials rmupc = (CustomLoginCredentials)credentials;
String ip = getIpAddr(request);
String sessionCode = (String)WebUtils.getHttpServletRequest(context).getSession().getAttribute(code);
if(rmupc.getCode() == null){
final String code = "login.code.tip";
messageContext.addMessage(
new MessageBuilder().error().code(code).arg("").defaultText(code).build());
return "error";
}
if (!rmupc.getCode().toUpperCase().equals(sessionCode.toUpperCase())) {
final String code = "login.code.error";
messageContext.addMessage(
new MessageBuilder().error().code(code).arg("").defaultText(code).build());
return "error";
}
Map<String,Object> param = new HashMap<String, Object>();
param.put("ip", ip);
rmupc.setParam(param);
}
// Validate login ticket
final String authoritativeLoginTicket = WebUtils.getLoginTicketFromFlowScope(context);
final String providedLoginTicket = WebUtils.getLoginTicketFromRequest(context);
if (!authoritativeLoginTicket.equals(providedLoginTicket)) {
this.logger.warn("Invalid login ticket " + providedLoginTicket);
final String code = "INVALID_TICKET";
messageContext.addMessage(
new MessageBuilder().error().code(code).arg(providedLoginTicket).defaultText(code).build());
return "error";
}
final String ticketGrantingTicketId = WebUtils.getTicketGrantingTicketId(context);
final Service service = WebUtils.getService(context);
if (StringUtils.hasText(context.getRequestParameters().get("renew")) && ticketGrantingTicketId != null && service != null) {
try {
final String serviceTicketId = this.centralAuthenticationService.grantServiceTicket(ticketGrantingTicketId, service, credentials);
WebUtils.putServiceTicketInRequestScope(context, serviceTicketId);
putWarnCookieIfRequestParameterPresent(context);
return "warn";
} catch (final TicketException e) {
if (e.getCause() != null && AuthenticationException.class.isAssignableFrom(e.getCause().getClass())) {
populateErrorsInstance(e, messageContext);
return "error";
}
this.centralAuthenticationService.destroyTicketGrantingTicket(ticketGrantingTicketId);
if (logger.isDebugEnabled()) {
logger.debug("Attempted to generate a ServiceTicket using renew=true with different credentials", e);
}
}
}
try {
WebUtils.putTicketGrantingTicketInRequestScope(context, this.centralAuthenticationService.createTicketGrantingTicket(credentials));
putWarnCookieIfRequestParameterPresent(context);
return "success";
} catch (final TicketException e) {
populateErrorsInstance(e, messageContext);
return "error";
}
}
private void populateErrorsInstance(final TicketException e, final MessageContext messageContext) {
try {
messageContext.addMessage(new MessageBuilder().error().code(e.getCode()).defaultText(e.getCode()).build());
} catch (final Exception fe) {
logger.error(fe.getMessage(), fe);
}
}
private void putWarnCookieIfRequestParameterPresent(final RequestContext context) {
final HttpServletResponse response = WebUtils.getHttpServletResponse(context);
if (StringUtils.hasText(context.getExternalContext().getRequestParameterMap().get("warn"))) {
this.warnCookieGenerator.addCookie(response, "true");
} else {
this.warnCookieGenerator.removeCookie(response);
}
}
public final void setCentralAuthenticationService(final CentralAuthenticationService centralAuthenticationService) {
this.centralAuthenticationService = centralAuthenticationService;
}
/**
* Set a CredentialsBinder for additional binding of the HttpServletRequest
* to the Credentials instance, beyond our default binding of the
* Credentials as a Form Object in Spring WebMVC parlance. By the time we
* invoke this CredentialsBinder, we have already engaged in default binding
* such that for each HttpServletRequest parameter, if there was a JavaBean
* property of the Credentials implementation of the same name, we have set
* that property to be the value of the corresponding request parameter.
* This CredentialsBinder plugin point exists to allow consideration of
* things other than HttpServletRequest parameters in populating the
* Credentials (or more sophisticated consideration of the
* HttpServletRequest parameters).
*
* @param credentialsBinder the credentials binder to set.
*/
public final void setCredentialsBinder(final CredentialsBinder credentialsBinder) {
this.credentialsBinder = credentialsBinder;
}
public final void setWarnCookieGenerator(final CookieGenerator warnCookieGenerator) {
this.warnCookieGenerator = warnCookieGenerator;
}
/**
* 获取IP地址
* @param request
* @return
*/
public String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}
message_zh_CN.proeprties 中添加
login.code.tip=\u8BF7\u8F93\u5165\u9A8C\u8BC1\u7801
login.code.error=\u9A8C\u8BC1\u7801\u8F93\u5165\u6709\u8BEF
login.ip.error=\u60A8\u7535\u8111\u7684ip\u4E0D\u5141\u8BB8\u767B\u5F55
package com.cc.flow;
import java.io.IOException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import com.wokejia.flow.ValidatorCodeUtil.ValidatorCode;
public class CaptchaImageCreateController implements Controller,
InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
}
@Override
public ModelAndView handleRequest(HttpServletRequest arg0,
HttpServletResponse response) throws Exception {
ValidatorCode codeUtil = ValidatorCodeUtil.getCode();
arg0.getSession().setAttribute("code", codeUtil.getCode());
// 禁止图像缓存。
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");
ServletOutputStream sos = null;
try {
// 将图像输出到Servlet输出流中。
sos = response.getOutputStream();
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(sos);
encoder.encode(codeUtil.getImage());
sos.flush();
sos.close();
} catch (Exception e) {
} finally {
if (null != sos) {
try {
sos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}
package com.cc.flow;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.Random;
/**
* <p class="detail">
* 验证码生成工具
* </p>
*
* @ClassName: ValidatorCodeUtil
* @version V1.0 @date 2012-4-9 下午06:59:25
* @author 罗伟俊
*
*/
public class ValidatorCodeUtil {
public static ValidatorCode getCode(){
// 验证码图片的宽度。
int width = 80;
// 验证码图片的高度。
int height = 30;
BufferedImage buffImg = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
Graphics2D g = buffImg.createGraphics();
// 创建一个随机数生成器类。
Random random = new Random();
// 设定图像背景色(因为是做背景,所以偏淡)
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
// 创建字体,字体的大小应该根据图片的高度来定。
Font font = new Font("微软雅黑", Font.HANGING_BASELINE, 28);
// 设置字体。
g.setFont(font);
// 画边框。
g.setColor(Color.BLACK);
g.drawRect(0, 0, width - 1, height - 1);
// 随机产生155条干扰线,使图象中的认证码不易被其它程序探测到。
// g.setColor(Color.GRAY);
// g.setColor(getRandColor(160, 200));
// for (int i = 0; i < 155; i++) {
// int x = random.nextInt(width);
// int y = random.nextInt(height);
// int xl = random.nextInt(12);
// int yl = random.nextInt(12);
// g.drawLine(x, y, x + xl, y + yl);
// }
// randomCode用于保存随机产生的验证码,以便用户登录后进行验证。
StringBuffer randomCode = new StringBuffer();
// 设置默认生成4个验证码
int length = 4;
// 设置备选验证码:包括"a-z"和数字"0-9"
String base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int size = base.length();
// 随机产生4位数字的验证码。
for (int i = 0; i < length; i++) {
// 得到随机产生的验证码数字。
int start = random.nextInt(size);
String strRand = base.substring(start, start + 1);
// 用随机产生的颜色将验证码绘制到图像中。
// 生成随机颜色(因为是做前景,所以偏深)
// g.setColor(getRandColor(1, 100));
// 调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生成
g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
g.drawString(strRand, 15 * i + 6, 24);
// 将产生的四个随机数组合在一起。
randomCode.append(strRand);
}
// 图象生效
g.dispose();
ValidatorCode code = new ValidatorCode();
code.image = buffImg;
code.code = randomCode.toString();
return code;
}
// 给定范围获得随机颜色
static Color getRandColor(int fc, int bc) {
Random random = new Random();
if (fc > 255)
fc = 255;
if (bc > 255)
bc = 255;
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}
/**
*
* <p class="detail">验证码图片封装</p>
*
* @ClassName: ValidatorCode
* @version V1.0 @date 2012-4-9 下午07:24:14
* @author 罗伟俊
*
*/
public static class ValidatorCode{
private BufferedImage image;
private String code;
/**
* <p class="detail">图片流</p>
* @return
*/
public BufferedImage getImage() {
return image;
}
/**
* <p class="detail">验证码</p>
* @return
*/
public String getCode() {
return code;
}
}
}
login-webflow.xml 中替换
<var name="credentials" class="com.cc.flow.CustomLoginCredentials" />
public class CustomLoginCredentials extends
RememberMeUsernamePasswordCredentials {
private static final long serialVersionUID = 1L;
private Map<String,Object> param;
/** The username. */
@NotNull
@Size(min=1,message = "required.code")
private String code;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Map<String, Object> getParam() {
return param;
}
public void setParam(Map<String, Object> param) {
this.param = param;
}
}
<view-state id="viewLoginForm" view="casLoginView" model="credentials">
<binder>
<binding property="username" />
<binding property="password" />
<binding property="code" />
</binder>
<on-entry>
<set name="viewScope.commandName" value="'credentials'" />
</on-entry>
<transition on="submit" bind="true" validate="true" to="realSubmit">
<evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" />
</transition>
</view-state>
casLoginView.jsp中添加验证码
<input class="sltextbg slinput5 edicheck" tabindex="3" id="code" size="10" name="code" autocomplete="off" />
<a href="javascript:;" onClick="img.src='captcha.htm?t='+new Date().getTime()" style="width:60px;height:30px;"><img id="img" width="60" height="30" src="captcha.htm" style="display: block;position: relative;float: right;padding-left: 5px;"/>换一个</a>