Shiro认证框架下,加入图形验证码


目录结构:

  1. 概述创建验证码异常类:CaptchaException.java
  2. 扩展shiro认证
  3. 验证码工具
  4. 验证码servlet
  5. 配置文件修改
  6. 修改登录页面
  7. 测试验证

[一]、概述

本文简单讲述在web应用整合shiro后,如何实现登录验证码认证的功能。

[二]、扩展shiro的认证

创建验证码异常类:CaptchaException.java

package com.micmiu.modules.support.shiro;

import org.apache.shiro.authc.AuthenticationException;

/**
 *
 * @author <a href="http://www.micmiu.com">Michael Sun</a>
 */
public class CaptchaException extends AuthenticationException {

	private static final long serialVersionUID = 1L;

	public CaptchaException() {

		super();

	}

	public CaptchaException(String message, Throwable cause) {

		super(message, cause);

	}

	public CaptchaException(String message) {

		super(message);

	}

	public CaptchaException(Throwable cause) {

		super(cause);

	}

}


扩展默认的用户认证的bean为:UsernamePasswordCaptchaToken.java

package com.micmiu.modules.support.shiro;

import org.apache.shiro.authc.UsernamePasswordToken;

/**
 * extends UsernamePasswordToken for captcha
 *
 * @author <a href="http://www.micmiu.com">Michael Sun</a>
 */
public class UsernamePasswordCaptchaToken extends UsernamePasswordToken {

	private static final long serialVersionUID = 1L;

	private String captcha;

	public String getCaptcha() {
		return captcha;
	}

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

	public UsernamePasswordCaptchaToken() {
		super();

	}

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

}


扩展原始默认的过滤为:FormAuthenticationCaptchaFilter.java

package com.micmiu.modules.support.shiro;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;

/**
 *
 * @author <a href="http://www.micmiu.com">Michael Sun</a>
 */
public class FormAuthenticationCaptchaFilter extends FormAuthenticationFilter {

	public static final String DEFAULT_CAPTCHA_PARAM = "captcha";

	private String captchaParam = DEFAULT_CAPTCHA_PARAM;

	public String getCaptchaParam() {

		return captchaParam;

	}

	protected String getCaptcha(ServletRequest request) {

		return WebUtils.getCleanParam(request, getCaptchaParam());

	}

	protected AuthenticationToken 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 UsernamePasswordCaptchaToken(username,
				password.toCharArray(), rememberMe, host, captcha);

	}

}


修改shiro认证逻辑:ShiroDbRealm.java

package com.micmiu.framework.web.v1.system.service;

import java.io.Serializable;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import com.micmiu.framework.web.v1.system.entity.Role;
import com.micmiu.framework.web.v1.system.entity.User;
import com.micmiu.modules.captcha.CaptchaServlet;
import com.micmiu.modules.support.shiro.CaptchaException;
import com.micmiu.modules.support.shiro.UsernamePasswordCaptchaToken;

/**
 * 演示用户和权限的认证,使用默认 的SimpleCredentialsMatcher
 *
 * @author <a href="http://www.micmiu.com">Michael Sun</a>
 */
public class ShiroDbRealm extends AuthorizingRealm {

	private UserService userService;

	/**
	 * 认证回调函数, 登录时调用.
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authcToken) throws AuthenticationException {
		UsernamePasswordCaptchaToken token = (UsernamePasswordCaptchaToken) authcToken;

		String username = token.getUsername();
		if (username == null) {
			throw new AccountException(
					"Null usernames are not allowed by this realm.");
		}
		// 增加判断验证码逻辑
		String captcha = token.getCaptcha();
		String exitCode = (String) SecurityUtils.getSubject().getSession()
				.getAttribute(CaptchaServlet.KEY_CAPTCHA);
		if (null == captcha || !captcha.equalsIgnoreCase(exitCode)) {
			throw new CaptchaException("验证码错误");
		}

		User user = userService.getUserByLoginName(username);
		if (null == user) {
			throw new UnknownAccountException("No account found for user ["
					+ username + "]");
		}
		return new SimpleAuthenticationInfo(new ShiroUser(user.getLoginName(),
				user.getName()), user.getPassword(), getName());

	}

	/**
	 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		ShiroUser shiroUser = (ShiroUser) principals.fromRealm(getName())
				.iterator().next();
		User user = userService.getUserByLoginName(shiroUser.getLoginName());
		if (user != null) {
			SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
			for (Role role : user.getRoleList()) {
				// 基于Permission的权限信息
				info.addStringPermissions(role.getAuthList());
			}
			return info;
		} else {
			return null;
		}
	}

	/**
	 * 更新用户授权信息缓存.
	 */
	public void clearCachedAuthorizationInfo(String principal) {
		SimplePrincipalCollection principals = new SimplePrincipalCollection(
				principal, getName());
		clearCachedAuthorizationInfo(principals);
	}

	/**
	 * 清除所有用户授权信息缓存.
	 */
	public void clearAllCachedAuthorizationInfo() {
		Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
		if (cache != null) {
			for (Object key : cache.keys()) {
				cache.remove(key);
			}
		}
	}

	@Autowired
	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	/**
	 * 自定义Authentication对象,使得Subject除了携带用户的登录名外还可以携带更多信息.
	 */
	public static class ShiroUser implements Serializable {

		private static final long serialVersionUID = -1748602382963711884L;
		private String loginName;
		private String name;

		public ShiroUser(String loginName, String name) {
			this.loginName = loginName;
			this.name = name;
		}

		public String getLoginName() {
			return loginName;
		}

		/**
		 * 本函数输出将作为默认的<shiro:principal/>输出.
		 */
		@Override
		public String toString() {
			return loginName;
		}

		public String getName() {
			return name;
		}
	}
}


修改web.xml文件,加入

	<servlet>
		<servlet-name>kaptcha</servlet-name>
		<servlet-class>
			com.google.code.kaptcha.servlet.KaptchaServlet
		</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>kaptcha</servlet-name>
		<url-pattern>/images/kaptcha.jpg</url-pattern>
	</servlet-mapping>


修改 applicationContext-shiro.xml 中的配置如下:

<!-- Shiro Filter -->
<bean id="myCaptchaFilter" class="com.micmiu.modules.support.shiro.FormAuthenticationCaptchaFilter"/>

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
	<property name="securityManager" ref="securityManager" />
	<property name="loginUrl" value="/login.do" />
	<property name="successUrl" value="/index.do" />
	<property name="filters">
	    <map>
	        <entry key="authc" value-ref="myCaptchaFilter"/>
	    </map>
	</property>
	<property name="filterChainDefinitions">
		<value>
			/login.do = authc
			/logout.do = logout
			/servlet/* = anon
			/images/** = anon
			/js/** = anon
			/css/** = anon
			/** = user
		</value>
	</property>
</bean>

页面中加入

<div class="field">
					<label for="captcha" class="field">验证码:</label> <input type="text"
						id="captcha" name="captcha" size="4" maxlength="4"
						class="required" />
				</div>
				<div class="field">
					<label for="codeImg" class="field"></label> <img title="点击更换" id="img_captcha"
						οnclick="javascript:refreshCaptcha();"
						src="servlet/captchaCode">(看不清<a href="javascript:void(0)" οnclick="javascript:refreshCaptcha()">换一张</a>)
				</div>


 

<script type="text/javascript">$(document).ready(function() {
var _captcha_id = "#img_captcha";
function refreshCaptcha() {
$(_captcha_id).attr("src","servlet/captchaCode?t=" + Math.random());
}
</script>


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值