Shiro和AJAX完美整合

ShiroAJAX完美整合

这是我第一次认认真真写博客,以前为了图快,结果写下来基本只有自己可以看懂。不过我感觉有经验就应该要和别人分享下,在分享的同时或许可以为这个问题找到更好的解决方案。

我在上学期5月份学完了Shiro,当初学时,看了半天的英文文档,最后还是不知道它为什么要这么干,只知道很多人说它很方便。在今年9月初时,我在次使用它,这次终于知道它的内部原理,但是感觉它的处理方式和我的上一个项目很相似。

这个为了实现远程服务器管理平台,我用上了Shiro,不过给我的第一个感觉是为什么它老是不按照我的业务方式来。最主要的是它在处理非法请求时,不是返回错误的字符串,而是直接跳转到登入界面,这个对于使用ajax来说简直是个噩耗。针对这个问题网上也有很多解决方案,我记得最清楚的是有一个人他把登入的地址改成json字符串,对于这个方案,我只能说不够灵活。算了,不说那么多了,直接说我的解决方案。

Shiro最主要的是拦截器,所以我们只要重写个拦截器就可以达到我们的目的,不管是直接请求还是ajax请求都可以直接处理。shiro处理拦截的类主要是FormAuthenticationFilter,所以我们对里面相应的方法进行重写即可。

/**
 * 
 */
package com.wms.studio.filter;

import java.io.IOException;
import java.io.PrintWriter;

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

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

/**
 * @author WMS
 * 
 */
public class CaptchaFormAuthenticationFilter extends FormAuthenticationFilter {

	private static final Logger log = LoggerFactory
			.getLogger(CaptchaFormAuthenticationFilter.class);

	/*
	 *	主要是针对登入成功的处理方法。对于请求头是AJAX的之间返回JSON字符串。
	 */
	@Override
	protected boolean onLoginSuccess(AuthenticationToken token,Subject subject,ServletRequest request,ServletResponse response)
			throws Exception {
		HttpServletRequest httpServletRequest = (HttpServletRequest) request;
		HttpServletResponse httpServletResponse = (HttpServletResponse) response;

		if (!"XMLHttpRequest".equalsIgnoreCase(httpServletRequest
				.getHeader("X-Requested-With"))) {// 不是ajax请求
			issueSuccessRedirect(request,response);
		} else {
			httpServletResponse.setCharacterEncoding("UTF-8");
			PrintWriter out = httpServletResponse.getWriter();
			out.println("{success:true,message:'登入成功'}");
			out.flush();
			out.close();
		}
		return false;
	}

	/**
	 * 主要是处理登入失败的方法
	 */
	@Override
	protected boolean onLoginFailure(AuthenticationToken token,AuthenticationException e,ServletResponse response) {
		if (!"XMLHttpRequest".equalsIgnoreCase(((HttpServletRequest) request)
				.getHeader("X-Requested-With"))) {// 不是ajax请求
			setFailureAttribute(request,e);
			return true;
		}
		try {
			response.setCharacterEncoding("UTF-8");
			PrintWriter out = response.getWriter();
			String message = e.getClass().getSimpleName();
			if ("IncorrectCredentialsException".equals(message)) {
				out.println("{success:false,message:'密码错误'}");
			} else if ("UnknownAccountException".equals(message)) {
				out.println("{success:false,message:'账号不存在'}");
			} else if ("LockedAccountException".equals(message)) {
				out.println("{success:false,message:'账号被锁定'}");
			} else {
				out.println("{success:false,message:'未知错误'}");
			}
			out.flush();
			out.close();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		return false;
	}

	/**
	 * 所有请求都会经过的方法。
	 */
	@Override
	protected boolean onAccessDenied(ServletRequest request,ServletResponse response) throws Exception {

		if (isLoginRequest(request,response)) {
			if (isLoginSubmission(request,response)) {
				if (log.isTraceEnabled()) {
					log.trace("Login submission detected.  Attempting to execute login.");
				}
				if ("XMLHttpRequest"
						.equalsIgnoreCase(((HttpServletRequest) request)
								.getHeader("X-Requested-With"))) {// 不是ajax请求
					String vcode = request.getParameter("vcode");
					HttpServletRequest httpservletrequest = (HttpServletRequest) request;
					String vvcode = (String) httpservletrequest
							.getSession()
							.getAttribute(
									com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
					if (vvcode == null || "".equals(vvcode)
							|| !vvcode.equals(vcode)) {
						response.setCharacterEncoding("UTF-8");
						PrintWriter out = response.getWriter();
						out.println("{success:false,message:'验证码错误'}");
						out.flush();
						out.close();
						return false;
					}
				}
				return executeLogin(request,response);
			} else {
				if (log.isTraceEnabled()) {
					log.trace("Login page view.");
				}
				// allow them to see the login page ;)
				return true;
			}
		} else {
			if (log.isTraceEnabled()) {
				log.trace("Attempting to access a path which requires authentication.  Forwarding to the "
						+ "Authentication url [" + getLoginUrl() + "]");
			}
			if (!"XMLHttpRequest"
					.equalsIgnoreCase(((HttpServletRequest) request)
							.getHeader("X-Requested-With"))) {// 不是ajax请求
				saveRequestAndRedirectToLogin(request,response);
			} else {
				response.setCharacterEncoding("UTF-8");
				PrintWriter out = response.getWriter();
				out.println("{message:'login'}");
				out.flush();
				out.close();
			}
			return false;
		}
	}
}

然后还需要告诉拦截器,你定义了这个拦截

<!-- Shiro Filter -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterfactorybean">
		<property name="securityManager" ref="securityManager" />
		<property name="loginUrl" value="/login.jsp" />
		<!-- <property name="successUrl" value="/" /> -->
		<property name="filters">
			<map>
				<entry key="authc">
					<bean class="com.wms.studio.filter.CaptchaFormAuthenticationFilter"></bean>
				</entry>
			</map>
		</property>
		<property name="filterChainDefinitions">
			<value>
				/extjs/** = anon
				/js/userservice.js= anon
				/resources/**=anon
				/kaptcha.jpg=anon
				/**=authc
			</value>
		</property>
	</bean>

这样基本就可以实现完美整合了。。。。。。。。。

看看我的效果

例子下载地址:http://download.csdn.net/detail/wu560130911/6295521


不懂或有问题的可以联系我,E-mail:560130911@163.com。

相关文章

JS原生Ajax操作(XMLHttpRequest) GET请求 POST请求 兼容性问题 利用iframe模拟ajax 实现表单提交的返回...
AJAX 每日更新前端基础,如果觉得不错,点个star吧 &#128515; https://github.com/WindrunnerMax/E...
踩坑Axios提交form表单几种格式 前后端分离的开发前后端, 前端使用的vue,后端的安全模块使用的SpringSe...
很早就听闻ajax的名声,但是却一直不知道怎么用,今天自己捣鼓了一下,竟然会用了,哈哈哈哈。 为了防止...
需要在服务器上进行哈 jquery的ajax方法: // jquery请求 $.ajax({ url: &quot;./server/slider.js...
Ajax函数封装ajax.js // Get / Post // 参数 get post // 是否异步 // 如何处理响应数据 // URL // var...