All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tech.mhuang.pacebox.springboot.auth.interceptor.OpAuthInterceptor Maven / Gradle / Ivy

The newest version!
package tech.mhuang.pacebox.springboot.auth.interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
import tech.mhuang.pacebox.core.exception.BusinessException;
import tech.mhuang.pacebox.core.util.CollectionUtil;
import tech.mhuang.pacebox.core.util.StringUtil;
import tech.mhuang.pacebox.springboot.auth.constant.AuthConstant;
import tech.mhuang.pacebox.springboot.core.constans.Global;
import tech.mhuang.pacebox.springboot.core.jackson.JsonUtil;
import tech.mhuang.pacebox.springboot.core.spring.start.SpringContextHolder;
import tech.mhuang.pacebox.springboot.protocol.GlobalHeader;
import tech.mhuang.pacebox.springboot.protocol.Result;
import tech.mhuang.pacebox.springboot.protocol.auth.AuthExcludeUrl;
import tech.mhuang.pacebox.springboot.protocol.auth.AuthUrl;
import tech.mhuang.pacebox.springboot.redis.commands.IRedisExtCommands;

import java.util.List;
import java.util.Objects;

/**
 * 拦截器
 *
 * @author mhuang
 * @since 1.0.0
 */
@Slf4j
public class OpAuthInterceptor implements HandlerInterceptor {

    @Setter
    private int redisDataBase;

    @Setter
    private boolean checkUrl;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (!(handler instanceof ResourceHttpRequestHandler)) {
            try {
                if (checkUrl) {
                    log.debug("拦截的URL:{},拦截类型:{}", request.getRequestURL().toString(), request.getMethod());
                    boolean flag = this.checkUrlIsNotLogin(getUri(request));
                    if (!flag) {
                        String headJson = request.getHeader(Global.GLOBAL_HEADER);
                        if (StringUtil.isNotBlank(headJson)) {
                            GlobalHeader globalHeader = JsonUtil.toData(headJson, GlobalHeader.class);
                            if (StringUtil.isNotBlank(globalHeader.getToken())) {
                                flag = this.checkUrlPower(globalHeader.getUserId(), request);
                                if (!flag) {
                                    throw new BusinessException(Result.SYS_FAILD, "您没有权限访问!");
                                }
                            } else {
                                //检查是否在排除的路径中
                                flag = this.checkUrlIsNotLogin(getUri(request));
                                if (!flag) {
                                    throw new BusinessException(Result.SYS_FAILD, "您没有权限访问!");
                                }
                            }
                        } else {
                            throw new BusinessException(Result.SYS_FAILD, "您没有权限访问!");
                        }
                    }
                }
            } catch (BusinessException e) {
                log.error("检查权限异常", e);
                this.writeJson(e.getCode(), e.getMessage(), response);
                return false;
            } catch (Exception e) {
                this.writeJson(Result.SYS_FAILD, "授权失败!", response);
                log.error("检查权限异常", e);
                return false;
            }
        }
        return true;
    }

    /**
     * 检查地址是否不需要登录
     *
     * @param uri url
     * @return boolean
     */
    private boolean checkUrlIsNotLogin(String uri) {
        //检查路径权限
        IRedisExtCommands repository = SpringContextHolder.getBean(IRedisExtCommands.class);
        log.debug("开始检查请求的URI:{}是否不需要登录", uri);
        return isFilterFlag(uri, repository, false, AuthConstant.NOT_LOGIN_VIST_URLS_CACHEKEY);
    }

    private boolean isFilterFlag(String uri, IRedisExtCommands repository, boolean filterFlag, String cacheExcludeKey) {
        List vos = repository.hgetList(redisDataBase, AuthConstant.AUTH_DICT_KEY, cacheExcludeKey, AuthExcludeUrl.class);
        if (CollectionUtil.isNotEmpty(vos)) {
            filterFlag = vos.parallelStream().anyMatch(vo -> (StringUtil.isNotBlank(vo.getUrl()) && (uri.startsWith(vo.getUrl()) || "*".equals(vo.getUrl()))));
        }
        return filterFlag;
    }

    /**
     * 写json数据
     *
     * @param code     状态码
     * @param message  信息
     * @param response 返回
     */
    private void writeJson(int code, String message, HttpServletResponse response) {
        try {
            Result result = Result.status(code,message);
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(403);
            response.getWriter().write(JsonUtil.toString(result));
            response.getWriter().flush();
        } catch (Exception ignored) {
        }
    }

    /**
     * 检查路径权限
     *
     * @param userId      用户id
     * @param httpRequest http请求
     */
    @SuppressWarnings("unchecked")
    private boolean checkUrlPower(String userId, HttpServletRequest httpRequest) {
        //检查权限排除路径地址
        String url = getUri(httpRequest);
        log.debug("开始检查请求的URI:{}是否具有访问权限", url);
        //检查路径权限
        IRedisExtCommands repository = SpringContextHolder.getBean(IRedisExtCommands.class);
        String cacheExcludeKey = AuthConstant.EXCLUDE_VIST_URLS_CACHEKEY;
        boolean filterFlag = isFilterFlag(url, repository, false, cacheExcludeKey);
        if (!filterFlag) {
            String cacheKey = AuthConstant.USER_VIST_URL_CACHEKEY;
            AuthUrl authUrl = repository.hget(redisDataBase, cacheKey, userId.concat("-").concat(url), AuthUrl.class);
            if (authUrl != null) {
                filterFlag = true;
            }
        }
        return filterFlag;
    }


    /**
     * Retrieves the current request servlet path.
     * Deals with differences between servlet specs (2.2 vs 2.3+)
     *
     * @param request the request
     * @return the servlet path
     */
    public static String getServletPath(HttpServletRequest request) {
        String servletPath = request.getServletPath();
        String requestUri = request.getRequestURI();
        // Detecting other characters that the servlet container cut off (like anything after ';')
        if (requestUri != null && servletPath != null && !requestUri.endsWith(servletPath)) {
            int pos = requestUri.indexOf(servletPath);
            if (pos > -1) {
                servletPath = requestUri.substring(requestUri.indexOf(servletPath));
            }
        }

        if (null != servletPath && !servletPath.isEmpty()) {
            return servletPath;
        }

        int startIndex = StringUtil.equals(request.getContextPath(), "") ? 0 : request.getContextPath().length();
        int endIndex = request.getPathInfo() == null ? Objects.requireNonNull(requestUri).length() : Objects.requireNonNull(requestUri).lastIndexOf(request.getPathInfo());

        if (startIndex > endIndex) {
            // this should not happen
            endIndex = startIndex;
        }

        return requestUri.substring(startIndex, endIndex);
    }

    /**
     * Gets the uri from the request
     *
     * @param request The request
     * @return The uri
     */
    public static String getUri(HttpServletRequest request) {
        // handle http dispatcher includes.
        String uri = (String) request.getAttribute("jakarta.servlet.include.servlet_path");
        if (uri != null) {
            return uri;
        }

        uri = getServletPath(request);
        if (uri != null && !uri.isEmpty()) {
            return uri;
        }

        uri = request.getRequestURI();
        return uri.substring(request.getContextPath().length());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy