shior 前后端分离项目Session失效后返回json字符串

最近公司在做APP项目,属于前后端分离,使用ajax请求后台传递JSON数据,但是现在有一个问题,shior默认的配置是session过期后直接跳转到Ligin请求,最后返回Login页面,但是前后端分离的项目都是通过ajax接受的,跳转也是由前台控制,这就导致了PC端与APP需要返回的数据类型不一致的问题。通过百度,找到一种可行的方案,贴出来以供参考。

通过继承  org.apache.shiro.web.filter.authc.FormAuthenticationFilter 类来重写  onAccessDenied方法可以达到这个效果。

1、重写onAccessDenied 方法 

package com.mlkj.modules.sys.security;

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

import com.alibaba.druid.wall.violation.ErrorCode;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.http.HttpRequest;
import org.springframework.stereotype.Service;

import com.mlkj.common.json.AjaxJson;
import com.mlkj.common.json.PrintJSON;
import com.mlkj.common.utils.StringUtils;
import com.mlkj.modules.sys.security.SystemAuthorizingRealm.Principal;
import com.mlkj.modules.sys.utils.UserUtils;

import java.io.PrintWriter;

/**
 * 表单验证(包含验证码)过滤类
 */
@Service
public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter {


    /**
     * onAccessDenied 方法会拦截在shior  shiroFilterChainDefinitions 配置中 value=authc 的请求
     * 方法说明: isLoginRequest 方法表示判断当前请求是否为登陆请求,shior会获取到当前请求并和配置文件中配置的登陆请求做比对,如果相同返回true,否则返回false;
     * isLoginSubmission 方法表示判断当前请求如果当前请求URL为登录地址时,判断是否为form提交。
     * executeLogin 方法表示是一个登陆方法 调用subject.login(token),如果登录成功,则调用onLoginSuccess();失败则调用onLoginFailure(),
     * AuthenticatingFilter.onLoginSuccess(): return true;
     * AuthenticatingFilter.onLoginFailure(): return false;
     * 最终会调用realm的doGetAuthenticationInfo
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        if (this.isLoginRequest(request, response)) {
            if (this.isLoginSubmission(request, response)) {
                return this.executeLogin(request, response);
            } else {
                return true;

            }
        } else {
           String header = ((HttpServletRequest) request).getHeader("Content-Type");
            if(header != null && header.equals("application/x-www-form-urlencoded")){
                response.setCharacterEncoding("UTF-8");
                PrintWriter out = response.getWriter();
                AjaxJson ajaxJson = new AjaxJson();
                ajaxJson.setErrorCode("notLogin");
                ajaxJson.setSuccess(false);
                ajaxJson.setMsg("user not login");
                out.print(ajaxJson.getJsonStr());
                out.flush();
                out.close();
            } else {
                this.saveRequestAndRedirectToLogin(request, response);
            }
            return false;
        }
    }
}

2 修改shior配置文件 中的 shiroFilterChainDefinitions  将  ${adminPath}/**  改为   authc (${adminPath}为我们项目的默认路径,根据自身项目来设置)

<!-- Shiro权限过滤过滤器定义 -->
	<bean name="shiroFilterChainDefinitions" class="java.lang.String">
		<constructor-arg>
			<value>
				/static/** = anon
				/userfiles/** = anon
				${adminPath}/sys/user/infoCareStatus = anon
				${adminPath}/sys/user/validateLoginName = anon
				${adminPath}/sys/user/validateMobile = anon
				${adminPath}/sys/user/validateMobileExist = anon
				${adminPath}/sys/user/resetPassword = anon
				${adminPath}/sys/register/** = anon
				${adminPath}/codeLogin/** = anon
				${adminPath}/soft/sysVersion/getAndroidVer = anon
				${adminPath}/soft/sysVersion/getIosVer = anon
				${adminPath}/api/** = anon
				${adminPath}/pay/** = anon
				${adminPath}/wechat/** = anon
				${adminPath}/cas = cas
				${adminPath}/login = authc
				${adminPath}/heartbeat = anon
				${adminPath}/logout = anon
				${adminPath}/** = authc
				/act/editor/** = user
				/act/rest/service/editor/** = perms[act:model:edit]
				/act/rest/service/model/** = perms[act:model:edit]
				/act/rest/service/** = user
				/ReportServer/** = user
				${adminPath}/hr/hrInterview/receive = anon
				${adminPath}/hr/hrOffer/receive = anon
			</value>
		</constructor-arg>
	</bean>

 

       onAccessDenied 方法会拦截在shior  shiroFilterChainDefinitions 配置中 value=authc 的请求,当请求被拒绝时会调用此方法。

       isLoginRequest 方法表示判断当前请求是否为登陆请求,shior会获取到当前请求并和配置文件中配置的登陆请求做比对,如果相同返回true,否则返回false;

  isLoginSubmission 方法表示判断当前请求如果当前请求URL为登录地址时,判断是否为form提交。

  executeLogin 方法表示是一个登陆方法 调用subject.login(token),如果登录成功,则调用onLoginSuccess();失败则调用onLoginFailure()。

  AuthenticatingFilter.onLoginSuccess(): return true;
  AuthenticatingFilter.onLoginFailure(): return false;
  最终会调用realm的doGetAuthenticationInfo

 如果当前请求是登陆请求,并且是form提交的话,就去进行登陆操作,否则的话直接通过。

如果当前请求非登陆请求,说明这个请求被拒绝了,这时候,通过header判断当前请求是不是ajax请求,如果是的话,说明是APP端连接,返回json格式数据,如果不是,说明是PC端连接,则调用  this.saveRequestAndRedirectToLogin(request, response); 跳转到默认的登陆页面。

写的不好请见谅!!!!!!!!!


版权声明:本文为qq_37612755原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。