shiro 返回json字符串 + 自定義filter

前言:

  在先後端分離的項目中, 在使用shiro的時候, 咱們絕大部分時候, 並不想讓瀏覽器跳轉到那個頁面去, 而是告訴前端, 你沒有登陸, 或者沒有訪問權限. 那這時候, 咱們就須要返回json字符串給前端, 讓前端解析後, 根據狀態執行相應的操做.html

實現:

因爲我如今的系統, 權限並不複雜, 因此在這裏, 我自定義了一個過濾器. 前端

固然, 若是想要更加省事, 能夠繼承user(org.apache.shiro.web.filter.authc.UserFilter) 或者 authc(org.apache.shiro.web.filter.authc.FormAuthenticationFilter) 過濾器, 固然, 也能夠是別的過濾器.java

1. 自定義過濾器web

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;

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

public class JsonAuthLoginFilter extends AccessControlFilter {

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
            throws Exception {
        Subject subject = SecurityUtils.getSubject();

        if(null != subject){
            if(subject.isRemembered()){
                return Boolean.TRUE;
            }
            if(subject.isAuthenticated()){
                return Boolean.TRUE;
            }
        }

        return Boolean.FALSE ;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        JsonResponse<Void> res = JsonResponse.noLogin("請先登陸");
        WebUtils.out((HttpServletResponse) response, res);
        return Boolean.FALSE ;
    }
}

這裏的JsonResponse是返回實體.spring

import com.alibaba.fastjson.annotation.JSONField;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

import java.io.Serializable;

@ApiModel
public class JsonResponse<T> implements Serializable {

    private static final long serialVersionUID = -7817536542662556767L;

    @ApiModelProperty("請求成功/失敗標誌")
    private boolean success;

    @ApiModelProperty("狀態碼, -1:沒有登陸, -2:沒有權限, -3:系統報錯, 0: 後臺返回錯誤信息, 1: 成功訪問")
    private int code;

    @ApiModelProperty("訪問提示信息")
    private String msg;

    @ApiModelProperty("後臺返回數據")
    private T data;

    public JsonResponse() {
    }

    public JsonResponse(boolean success) {
        this();
        this.success = success;
    }

    public JsonResponse(boolean success, String msg) {
        this(success);
        this.msg = msg;
    }

    public JsonResponse(boolean success, String msg, int code) {
        this(success, msg);
        this.code = code;
    }

    public JsonResponse(boolean success, String msg, int code, T data) {
        this(success, msg, code);
        this.data = data;
    }

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public static JsonResponse<Void> SUCCESS = new JsonResponse<>(true);

    public static <T> JsonResponse<T> success(T data) {
        return new JsonResponse<>(true, null, JsonResStateEnum.SUCCESS, data);
    }

    public static <T> JsonResponse<T> success(T data, String msg) {
        return new JsonResponse<>(true, msg, JsonResStateEnum.SUCCESS, data);
    }

    public static <T> JsonResponse<T> error(String msg) {
        return new JsonResponse<>(false, msg, JsonResStateEnum.USER_ERROR);
    }

    public static <T> JsonResponse<T> error(String msg,  T data) {
        return new JsonResponse<>(false, msg, JsonResStateEnum.USER_ERROR, data);
    }

    public static <T> JsonResponse<T> error(String msg, int code) {
        return new JsonResponse<>(false, msg, code);
    }

    public static <T> JsonResponse<T> noLogin(String msg) {
        return new JsonResponse<>(false, msg, JsonResStateEnum.NO_LOGIN);
    }

    public static <T> JsonResponse<T> noPermission(String msg) {
        return new JsonResponse<>(false, msg, JsonResStateEnum.NO_PERMISSION);
    }
}

JsonResStateEnum是自定義狀態枚舉apache

public interface JsonResStateEnum  {

    /**
     * 沒有登陸時的狀態
     */
    public static final  Integer NO_LOGIN = -1;

    /**
     * 沒有訪問權限時的狀態
     */
    public static final  Integer NO_PERMISSION = -2;

    /**
     * 系統錯誤時的錯誤, 不可掌控錯誤
     */
    public static final  Integer SYSTEM_ERROR = -3;

    /**
     * token驗證錯誤
     */
    public static final Integer TOKEN_ERROR = -4;

    /**
     * 由用戶自定義返回的錯誤, 受用戶掌控
     */
    public static final  Integer USER_ERROR = 0;

    /**
     * 正常狀態
     */
    public static final  Integer SUCCESS = 1;

}

WebUtils.out是自定義的方法, 意在返回json字符串json

public static  void out(HttpServletResponse response, JsonResponse jsonObj){
        PrintWriter out = null;
        try {
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json; charset=utf-8");
            out = response.getWriter();
            out.write(JSON.toJSONString(jsonObj));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                out.close();
            }
        }
}

經過這個過濾器, 能夠過濾沒有登陸的用戶, 並將json字符串返回給前端.後端

可是, 若是我登陸以後, 去訪問沒有權限的資源, 這樣子就不能解決了. 須要一個全局錯誤處理.api

 

2. 全局錯誤處理瀏覽器

import com.alibaba.fastjson.JSON;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.session.UnknownSessionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyMvcExceptionHandler implements HandlerExceptionResolver {

    protected final Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {

        logger.error(ex.getMessage(), ex);

        if (ex instanceof UnauthenticatedException || ex instanceof AuthenticationException || ex instanceof UnknownSessionException) {
            return outJson(request, response, JsonResponse.noLogin("請先登陸"));
        }
        if (ex instanceof UnauthorizedException || ex instanceof AuthorizationException) {
            return outJson(request, response, JsonResponse.noPermission("沒有訪問權限"));
        }
        return outJson(request, response, JsonResponse.error(ex.getMessage(), JsonResStateEnum.SYSTEM_ERROR));
    }

    private ModelAndView outJson(HttpServletRequest request, HttpServletResponse response, JsonResponse res) {
        ModelAndView mv = new ModelAndView();
        /*  使用response返回    */
        response.setStatus(HttpStatus.OK.value()); //設置狀態碼
        response.setContentType(MediaType.APPLICATION_JSON_VALUE); //設置ContentType
        response.setCharacterEncoding("UTF-8"); //避免亂碼
        response.setHeader("Cache-Control", "no-cache, must-revalidate");
        try {
            String json = JSON.toJSONString(res);
            response.getWriter().write(json);
        } catch (IOException e) {
            logger.error("與客戶端通信異常:" + e.getMessage(), e);
        }

        return mv;
    }
}

 

3. 配置

在application.xml配置文件中

<bean id="exceptionHandler" class="common.myexception.MyMvcExceptionHandler"/>
<bean name="loginFilter" class="shiro.filter.JsonAuthLoginFilter" /> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="loginUrl" value="${shiro.loginUrl}"/> <property name="filters"> <map> <entry key="login" value-ref="loginFilter" /> </map> </property> <property name="filterChainDefinitions"> <value> /logout=logout /user/retrievePwd = anon /user/signOut = anon /user/loginGet = anon /swagger-ui.html = anon /swagger-resources = anon /swagger-resources/** = anon /v2/api-docs = anon /webjars/** = anon /webjars/springfox-swagger-ui/** = anon /user/login = anon /user/register = anon /** = login </value> </property> </bean>

 

 

4. 結果:

 

相關文章
相關標籤/搜索