springMVC+shiro的权限管理和异常统一处理

springMVC+shiro的权限管理和异常统一处理
SpringMVC+shiro的配置请参照网上其他博文,本文主要介绍如何使用shiro,动态管控用户的url请求。如何自定义filter,让前端页面通过返回的异常状态码进行统一的弹窗提示。
使用shiro后发现,当请求不符合过滤器要求时,会自动跳转到unauthorizedUrl页面,而我想实现的是通过后端返回不同的异常状态码,前端ajax判断后进行弹窗提示,这样用户体验上会更友好一些。具体做法是通过自定义shiro的filter来实现的。
首先在shiro的配置文件中配置自定义的filter:
	<bean id="loginFilter" class="com.cmcc.hygcc.comm.shiro.LoginFilter"></bean>
	<bean id="myFilter" class="com.cmcc.hygcc.comm.shiro.MyFilter"></bean>
	<!-- Shiro主过滤器本身功能十分强大,其强大之处就在于它支持任何基于URL路径表达式的、自定义的过滤器的执行 -->
	<!-- Web应用中,Shiro可控制的Web请求必须经过Shiro主过滤器的拦截,Shiro对基于Spring的Web应用提供了完美的支持 -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<!-- Shiro的核心安全接口,这个属性是必须的 -->
		<property name="securityManager" ref="securityManager" />
		<!-- 要求登录时的链接(可根据项目的URL进行替换),非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面 -->
		<property name="loginUrl" value="/" />
		<!-- 登录成功后要跳转的连接(本例中此属性用不到,因为登录成功后的处理逻辑在LoginController里硬编码为main.jsp了) -->
		<property name="successUrl" value="/index.htm" />
		<!-- 用户访问未对其授权的资源时,所显示的连接 -->
		<!-- 若想更明显的测试此属性可以修改它的值,如unauthor.jsp,然后用[玄玉]登录后访问/admin/listUser.jsp就看见浏览器会显示unauthor.jsp -->
		<property name="unauthorizedUrl" value="/reLogin" />
		<property name="filters">
			<map>
				<entry key="myFilter" value-ref="myFilter" />
				<!-- 覆盖authc过滤器,使得未登录的ajax请求返回401状态 -->
				<entry key="authc" value-ref="loginFilter" />
			</map>
		</property>
		<!-- Shiro连接约束配置,即过滤链的定义 -->
		<!-- 此处可配合我的这篇文章来理解各个过滤连的作用http://blog.csdn.net/jadyer/article/details/12172839 -->
		<!-- 下面value值的第一个'/'代表的路径是相对于HttpServletRequest.getContextPath()的值来的 -->
		<!-- anon:它对应的过滤器里面是空的,什么都没做,这里.do和.jsp后面的*表示参数,比方说login.jsp?main这种 -->
		<!-- authc:该过滤器下的页面必须验证后才能访问,它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter -->
		<property name="filterChainDefinitions">
			<value>
				/=anon
				/font/**=anon
				/login.jsp=anon
				/jcaptcha*=anon
				/images/**=anon
				/js/**=anon
				/css/**=anon
				/system/getSalt*=anon
				/loginCheck=anon
				/login=anon
				/druid=anon
				/reLogin=anon
				/index.htm=authc
				/logout.htm=authc
				/system/navigation/get=authc
				/dics/list=authc
				/**=myFilter
			</value>
		</property>
	</bean>
其中包含两个filter,loginFilter和MyFilter,loginFilter主要是覆盖了自带的authc过滤器,让未登录的请求统一返回401。MyFilter是用于过滤需要权限校验的请求。

import java.io.IOException;

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

import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.StringUtils;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;

import com.cmcc.hygcc.comm.dao.CommonDao;

/**
 * @Type LoginFilter.java
 * @Desc 用于自定义过滤器,过滤用户请求时是否是登录状态
 * @author Zero
 * @date 2017年2月6日 上午9:06:15
 * @version 
 */
public class LoginFilter extends AuthorizationFilter {
    @Autowired
    public CommonDao dao;

    @Override
    protected boolean isAccessAllowed(ServletRequest req, ServletResponse resp, Object arg2)
            throws Exception {
        Subject subject = getSubject(req, resp);
        if (null != subject.getPrincipals()) {
            return true;
        }
        return false;
    }

    /**
     * 会话超时或权限校验未通过的,统一返回401,由前端页面弹窗提示
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response)
            throws IOException {
        if (isAjax((HttpServletRequest) request)) {
            WebUtils.toHttp(response).sendError(401);
        } else {
            String unauthorizedUrl = getUnauthorizedUrl();
            if (StringUtils.hasText(unauthorizedUrl)) {
                WebUtils.issueRedirect(request, response, unauthorizedUrl);
            } else {
                WebUtils.toHttp(response).sendError(401);
            }
        }

        return false;
    }

    private boolean isAjax(HttpServletRequest request) {
        String header = request.getHeader("x-requested-with");
        if (null != header && "XMLHttpRequest".endsWith(header)) {
            return true;
        }
        return false;
    }
}

import java.io.IOException;
import java.util.Set;

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

import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.StringUtils;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;

import com.cmcc.hygcc.comm.dao.CommonDao;

/**
 * @Type MyFilter.java
 * @Desc 用于自定义过滤器,过滤用户请求是否被授权
 * @author Zero
 * @date 2017年2月6日 上午9:06:15
 * @version 
 */
public class MyFilter extends AuthorizationFilter {
    @Autowired
    public CommonDao dao;

    @SuppressWarnings("unchecked")
    @Override
    protected boolean isAccessAllowed(ServletRequest req, ServletResponse resp, Object arg2)
            throws Exception {
        HttpServletRequest request = (HttpServletRequest) req;
        //获取请求路径
        String path = request.getServletPath();
        Subject subject = getSubject(req, resp);
        if (null != subject.getPrincipals()) {
            //根据session中存放的用户权限,比对路径,如果拥有该权限则放行
            Set<String> userPrivileges = (Set<String>) request.getSession()
                    .getAttribute("USER_PRIVILEGES");
            if (null != userPrivileges && userPrivileges.contains(path)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 会话超时或权限校验未通过的,统一返回401,由前端页面弹窗提示
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response)
            throws IOException {
        if (isAjax((HttpServletRequest) request)) {
            WebUtils.toHttp(response).sendError(401);
        } else {
            String unauthorizedUrl = getUnauthorizedUrl();
            if (StringUtils.hasText(unauthorizedUrl)) {
                WebUtils.issueRedirect(request, response, unauthorizedUrl);
            } else {
                WebUtils.toHttp(response).sendError(401);
            }
        }

        return false;
    }

    private boolean isAjax(HttpServletRequest request) {
        String header = request.getHeader("x-requested-with");
        if (null != header && "XMLHttpRequest".endsWith(header)) {
            return true;
        }
        return false;
    }
}

主要的判断逻辑如下:当收到ajax请求,且该请求未授权时,返回错误码401。下面贴出前端ajax的处理代码:
$.ajaxSetup({
	cache:false,
        error : function(XMLHttpRequest, textStatus,errorThrown) { 
            switch (XMLHttpRequest.status){  
	            case(401): 
	            	tempAlert("会话超时或访问未授权,即将跳转到登录页!"); 
	            	setInterval("toLoginPage()",3000);
                break;
                default:  
                    tempAlert("网络连接已断开!"); 
            }
        }
});

由于前端有部分超链接,对超链接也做了ajax的封装,每个超链接通过onclick方法调用ajaxHref函数,代码如下。这样就可以实现不论前端页面是超链接或是ajax请求,在请求未授权时,页面都会统一弹出确认窗口,并自动跳转到登录页。
function ajaxHref(url){
			$.ajax({
				type : 'GET',
				url : url,
				async : false,
				success:function(){
					window.location.href=url;
				}
			});
		}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值