Shiro(3)实现验证码认证

验证码是有效防止暴力破解的一种手段,常用做法是在服务端产生一串随机字符串与当前用户会话关联(我们通常说的放入 Session),然后向终端用户展现一张经过“扰乱”的图片,只有当用户输入的内容与服务端产生的内容相同时才允许进行下一步操作

产生验证码

作为演示,我们选择开源的验证码组件 kaptcha。这样,我们只需要简单配置一个 Servlet,页面通过 IMG 标签就可以展现图形验证码。

	
		kaptcha
		
			com.google.code.kaptcha.servlet.KaptchaServlet
		
	
	
		kaptcha
		/images/kaptcha.jpg
	


扩展 UsernamePasswordTokenShiro 表单认证,页面提交的用户名密码等信息,用 UsernamePasswordToken 类来接收,很容易想到,要接收页面验证码的输入,我们需要扩展此类:


package javacommon.shiro;

import org.apache.shiro.authc.UsernamePasswordToken;

public class CaptchaUsernamePasswordToken extends UsernamePasswordToken {
	//验证码字符串
	private String captcha;

	public CaptchaUsernamePasswordToken(String username, char[] password,
			boolean rememberMe, String host, String captcha) {
		super(username, password, rememberMe, host);
		this.captcha = captcha;
	}

	public String getCaptcha() {
		return captcha;
	}

	public void setCaptcha(String captcha) {
		this.captcha = captcha;
	}
	
}

扩展 FormAuthenticationFilter

接下来我们扩展 FormAuthenticationFilter 类

package javacommon.shiro;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CaptchaFormAuthenticationFilter extends FormAuthenticationFilter {
	private static final Logger LOG = LoggerFactory.getLogger(CaptchaFormAuthenticationFilter.class);
	
	public CaptchaFormAuthenticationFilter() {
	}
	@Override
	/**
	 * 登录验证
	 */
	protected boolean executeLogin(ServletRequest request,
			ServletResponse response) throws Exception {
		CaptchaUsernamePasswordToken token = createToken(request, response);
		try {
			/*图形验证码验证*/
			doCaptchaValidate((HttpServletRequest) request, token);
			Subject subject = getSubject(request, response);
			subject.login(token);//正常验证
			LOG.info(token.getUsername()+"登录成功");
			return onLoginSuccess(token, subject, request, response);
		}catch (AuthenticationException e) {
			LOG.info(token.getUsername()+"登录失败--"+e);
			return onLoginFailure(token, e, request, response);
		}
	}

	// 验证码校验
	protected void doCaptchaValidate(HttpServletRequest request,
			CaptchaUsernamePasswordToken token) {
//session中的图形码字符串
		String captcha = (String) request.getSession().getAttribute(
				com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
//比对
		if (captcha != null && !captcha.equalsIgnoreCase(token.getCaptcha())) {
			throw new IncorrectCaptchaException("验证码错误!");
		}
	}

	@Override
	protected CaptchaUsernamePasswordToken createToken(ServletRequest request,
			ServletResponse response) {
		String username = getUsername(request);
		String password = getPassword(request);
		String captcha = getCaptcha(request);
		boolean rememberMe = isRememberMe(request);
		String host = getHost(request);

		return new CaptchaUsernamePasswordToken(username,
				password.toCharArray(), rememberMe, host, captcha);
	}

	public static final String DEFAULT_CAPTCHA_PARAM = "captcha";

	private String captchaParam = DEFAULT_CAPTCHA_PARAM;

	public String getCaptchaParam() {
		return captchaParam;
	}

	public void setCaptchaParam(String captchaParam) {
		this.captchaParam = captchaParam;
	}

	protected String getCaptcha(ServletRequest request) {
		return WebUtils.getCleanParam(request, getCaptchaParam());
	}
	
//保存异常对象到request
	@Override
	protected void setFailureAttribute(ServletRequest request,
			AuthenticationException ae) {
		request.setAttribute(getFailureKeyAttribute(), ae);
	}
}



前面验证码校验不通过,我们抛出一个异常 IncorrectCaptchaException,此类继承 AuthenticationException,之所以需要扩展一个新的异常类,为的是在页面能更精准显示错误提示信息。


package javacommon.shiro;

import org.apache.shiro.authc.AuthenticationException;

public class IncorrectCaptchaException extends AuthenticationException {

	public IncorrectCaptchaException() {
		super();
	}

	public IncorrectCaptchaException(String message, Throwable cause) {
		super(message, cause);
	}

	public IncorrectCaptchaException(String message) {
		super(message);
	}

	public IncorrectCaptchaException(Throwable cause) {
		super(cause);
	}
}

Filter的配置及使用




	
	
		
		
		
		
		
		
		
		
		
			
				
			
		
		
		
			
				/login.jsp = authc
				/pages/* = authc
				/index.jsp* = authc
				/logout.do = logout
				
			
		
	

	
	

	
	
		
	

	

	

	
	
		
	


登录页面:


<%@page import="org.apache.shiro.web.filter.authc.FormAuthenticationFilter"%>
<%@page import="javacommon.shiro.IncorrectCaptchaException"%>
<%@page import="org.apache.shiro.authc.AuthenticationException"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%
	String path = request.getContextPath();
	String basePath = request.getScheme() + "://"
			+ request.getServerName() + ":" + request.getServerPort()
			+ path + "/";
%>





Insert title here





	<%
		Object obj = request
				.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
		String msg = "";
		if (obj != null) {
			if (obj instanceof IncorrectCaptchaException)
				msg = "验证码错误!";
			else 
				msg = "账号或密码错误!";
		}
		
		out.println("
" + msg + "
"); %>

用户帐号:
登录密码:
验证码:
  验证码(看不清换一张)


你可能感兴趣的