zoukankan      html  css  js  c++  java
  • shiro 返回json字符串 + 自定义filter

    前言:

      在前后端分离的项目中, 在使用shiro的时候, 我们绝大部分时候, 并不想让浏览器跳转到那个页面去, 而是告诉前端, 你没有登录, 或者没有访问权限. 那这时候, 我们就需要返回json字符串给前端, 让前端解析后, 根据状态执行相应的操作.

    实现:

    由于我现在的系统, 权限并不复杂, 所以在这里, 我自定义了一个过滤器. 

    当然, 如果想要更加省事, 可以继承user(org.apache.shiro.web.filter.authc.UserFilter) 或者 authc(org.apache.shiro.web.filter.authc.FormAuthenticationFilter) 过滤器, 当然, 也可以是别的过滤器.

    1. 自定义过滤器

    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是返回实体.

    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是自定义状态枚举

    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字符串

    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字符串返回给前端.

    但是, 如果我登录之后, 去访问没有权限的资源, 这样子就不能解决了. 需要一个全局错误处理.

    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. 结果:

     

  • 相关阅读:
    python 协程
    python 打印乘法表
    python 线程池
    python 队列
    开发react 应用最好用的脚手架 create-react-app
    React面试题
    修改了背景透明度
    低门槛彻底理解JavaScript中的深拷贝和浅拷贝
    Web Worker 使用教程
    Vue2 实现时空穿梭框功能模块
  • 原文地址:https://www.cnblogs.com/elvinle/p/9269117.html
Copyright © 2011-2022 走看看