全局权限控制

Posted IT的鱼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了全局权限控制相关的知识,希望对你有一定的参考价值。

public class AppContext 
    private static ThreadLocal<User> currentUserHolder = new ThreadLocal<>();

    private static void setCurrentUser(User user) 
        currentUserHolder.set(user);
    

    public static User getCurrentUser() 
        return currentUserHolder.get();
    

    public static void clearAll() 
        currentUserHolder.remove();
    

    /**
     * 注意 千万不要注释此代码,涉及安全性相关
     */
    public static void checkAndminRole() 
        User currentUser = AppContext.getCurrentUser();
        if (currentUser == null) 
            throw new BadRequestException("无权限访问此资源");
        
        if (!"superadmin".equals(currentUser.getRoleId())) 
            throw new BadRequestException("无权限访问此资源");
        
    
 @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException 
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;

        //判断如果是APP请求,则直接通过
        String requestURI = httpServletRequest.getRequestURI();
        if (requestURI.startsWith("/e/welink") ||
                requestURI.startsWith("/e/test/welink") ||
                requestURI.startsWith("/e/approve/waitApprove") ||
                requestURI.startsWith("/e/page/applicationPage") ||
                requestURI.startsWith("/e/ows/user/listRole") ||
                requestURI.endsWith(".ttf") ||
                requestURI.endsWith(".woff") ||
                requestURI.endsWith(".eot") ||
                requestURI.endsWith(".woff2") ||
                requestURI.endsWith(".css") ||
                requestURI.endsWith(".js") ||
                requestURI.endsWith(".png") ||
                requestURI.endsWith(".jpg") ||
                requestURI.endsWith(".wav") ||
                requestURI.endsWith(".xlsx") ||
                requestURI.endsWith(".svg") ||
                requestURI.startsWith("/e/api/csp/") ||
                requestURI.endsWith("/e/api/important_contact/all") ||
                requestURI.contains("getRepOffAndIndustry") ||
                requestURI.contains("getAllQcLine") ||
                requestURI.contains("feginAsp") ||
                requestURI.contains("/api/urgnetProblem") ||
                requestURI.contains("/api/policystu") ||
                requestURI.contains("/problemThroughTrain") ||
                requestURI.contains("/clientIndex")
            // requestURI.endsWith("/e/promotion/test")
        ) 
            chain.doFilter(request, response);
            return;
        
        if (requestURI.indexOf("/e/page") != -1) 
            if (isMSBrowser(httpServletRequest)) 
                response.setCharacterEncoding("gbk");
                PrintWriter out = response.getWriter();
                out.println("<div>本系统不支持 IE EDGE 等浏览器,推荐使用 Google Chrome浏览器,谢谢。</div>");
                return;
            
        
        HttpSession session = httpServletRequest.getSession();
        UserInfoBean uiBean = (UserInfoBean) session
                .getAttribute(SsoConstants.SESSION_USER_INFO_KEY);
        if (uiBean == null)    //会话已经超时
            if (CommonUtil.isAjax(httpServletRequest))    //ajax请求会话超时,filter不会进入统一异常拦截
                Map<String, String> map = new HashMap<>();
                map.put("code", "401");
                response.setCharacterEncoding("utf-8");
                response.getWriter().print(JSONObject.toJSON(map));
                return;
            
            try 
                // 从 sso 跳转回来 回到当前访问的 url
                SsoUtil.loginAndRedirect2AppCurrentURL((HttpServletRequest) request,
                        (HttpServletResponse) response);
                return;
             catch (Exception e) 
                e.printStackTrace();
            
         else 
            try 
                User token = null;
                try (Jedis jedis = jedisPool.getResource()) 
                    String redisKey = "userInfo_" + uiBean.getUid();
                    String tokenStr = jedis.get(redisKey);
                    if (StringUtils.isNotBlank(tokenStr)) 
                        token = JSON.parseObject(tokenStr, User.class);
                    
                    if (token == null) //|| token.getRootList().size() == 0
                        Result r = userService.login((HttpServletRequest) request,
                                (HttpServletResponse) response);
                        token = (User) r.getData();
                        if ("N".equals(token.getIsVaild())) 
                            if (CommonUtil.isAjax(httpServletRequest))    //ajax请求会话超时,filter不会进入统一异常拦截
                                throw new BadRequestException("此账号已被禁用,如需开通,请联系系统管理员 王超伟 w00509928 !");
                             else 
                                response.setCharacterEncoding("gbk");
                                response.getWriter().println("此账号已被禁用,如需开通,请联系系统管理员 王超伟 w00509928 !");
                                return;
                            
                        

                        // "审批"跳转流程
                        if (token.getIsExists()) 
                            // 用户表"存在"用户
                            Boolean redirect2ApplicationPage = approveLoginFilter.redirectWithUserExist(token);
                            if (redirect2ApplicationPage) 
                                ((HttpServletResponse) response).sendRedirect(((HttpServletRequest) request).getContextPath() + "/page/applicationPage?agentId=" + token.getUserAgentId());
                                return;
                            
                         else 
                            // 用户表"不存在"用户
                            Map<String, Object> newUserMap = approveLoginFilter.getNewUserByOldAgentId(token); // 查看是否更换账号
                            if (ObjectUtils.isEmpty(newUserMap)) 
                                // 没有更换账号,则表示完全为一个新的账户,按照正常的流程
                                approveLoginFilter.redirectWithUserNotExist(token);
                                ((HttpServletResponse) response).sendRedirect(((HttpServletRequest) request).getContextPath() + "/page/applicationPage?agentId=" + token.getUserAgentId());
                                return;
                             else 
                                // 更换了账号,则需要重新跳转至 用户表"存在"用户流程
                                User newUser = new User();
                                newUser.setId((String) newUserMap.get("ID"));
                                newUser.setUserAgentId((String) newUserMap.get("USER_AGENTID"));
                                newUser.setUserEmail((String) newUserMap.get("USER_EMAIL"));
                                newUser.setUserPhono((String) newUserMap.get("USER_PHONE"));
                                newUser.setCreateTime((Long) newUserMap.get("CREATE_DATE"));
                                newUser.setRoleId((String) newUserMap.get("ROLE_ID"));
                                newUser.setQc_line((String) newUserMap.get("QC_LINE"));
                                newUser.setRep_off((String) newUserMap.get("REP_OFF"));
                                Boolean redirect2ApplicationPage = approveLoginFilter.redirectWithUserExist(newUser);
                                if (redirect2ApplicationPage) 
                                    ((HttpServletResponse) response).sendRedirect(((HttpServletRequest) request).getContextPath() + "/page/applicationPage?agentId=" + token.getUserAgentId());
                                    return;
                                 else 
                                    // 重新登录
                                    Result loginResult = userService.login((HttpServletRequest) request, (HttpServletResponse) response);
                                    token = (User) loginResult.getData();
                                
                            
                        

                        // 加载整改配置角色
                        userService.setRectRole(token);
                        // 加载菜单、权限等
                        userService.loadUserResource(token);
//                        session.setAttribute("userInfo", token);
                        logUtils.log("登录", null, token.getUserAgentId(), token.getId());
                        dao.commit();
                        jedis.set(redisKey, JSON.toJSONString(token));
                        log.info("从数据库中加载用户信息");
                    
                    // 设置过期时间 单位(秒)
                    jedis.expire(redisKey, EXP_TIME);
                
                Method m = AppContext.class.getDeclaredMethod("setCurrentUser", User.class);
                m.setAccessible(true);
                m.invoke(null, token);
                chain.doFilter(request, response);
             catch (Exception ex) 
                log.error(ex.getMessage(), ex);
             finally 
                AppContext.clearAll();
                try 
                    dao.close();
                 catch (Exception e) 
                    e.printStackTrace();
                    log.error(e.getMessage(), e);
                
            
        
    

@Aspect
@Configuration
public class TransactionAop 

    private static TransactionAop transactionAop;

    private Dao dao;

    /**
     * api与二级菜单对应关系
     */
    private static LinkedListMultimap<String, String> URL_PID_MAPPING = LinkedListMultimap.create();

    @Autowired
    public void setDao(Dao dao) throws Exception 
        this.dao = dao;
        transactionAop = this;
        loadMapping();
    

    /**
     * api与二级菜单对应关系
     *
     * @throws Exception
     */
    public static void loadMapping() throws Exception 
        String sql = "select t.*,t.rowid from t_ows_resource t where t.type=3 order by length(t.url) desc";
        List<Map<String, Object>> list =
                transactionAop.dao.queryListBySql(sql, null);
        for (Map<String, Object> stringObjectMap : list) 
            URL_PID_MAPPING.put((String) stringObjectMap.get("URL"),
                    (String) stringObjectMap.get("PID"));
        
    

    @Pointcut("execution(public * e.itr..*Controller.*(..))")
    public void exeController() 
    

    @Pointcut("execution(public * e.itr..*Task.*(..))")
    public void exeTask() 
    

    @Around("exeController()")
    public Object doControllerAround1(ProceedingJoinPoint pjp) throws Throwable 
        return this.doTransaction(pjp);
    

    @Around("exeTask()")
    public Object doTaskAround(ProceedingJoinPoint pjp) throws Throwable 
        return this.doTaskTransaction(pjp);
    

    private Object doTaskTransaction(ProceedingJoinPoint pjp) throws Throwable 
        Object result = null;
        try 
            // result的值就是被拦截方法的返回值
            result = pjp.proceed();
            dao.commit();
         catch (Exception ex) 
            dao.rollback();
            throw ex;
         finally 
            dao.close();
        
        return result;
    

    private Object doTransaction(ProceedingJoinPoint pjp) throws Throwable 
        Object result = null;
        try 
            checkApiRight(pjp);
            // result的值就是被拦截方法的返回值
            result = pjp.proceed();
            dao.commit();
         catch (Exception ex) 
            dao.rollback();
            throw ex;
         finally 
            dao.close();
        
        return result;
    

    private void checkApiRight(ProceedingJoinPoint pjp) throws Exception 
        Class<?> classTarget = pjp.getTarget().getClass();
        RequestMapping rm1 = classTarget.getAnnotation(RequestMapping.class);
        if (rm1 == null || rm1.value() == null ||
                rm1.value().length == 0) 
            return;
        
        String url = rm1.value()[0];
        // 页面不拦截
        if (url.startsWith("/page") || url.contains("welink")) 
            return;
        
        // 拼接完整url
        String methodName = pjp.getSignature().getName();
        Class<?>[] par = ((MethodSignature) pjp.getSignature()).getParameterTypes();
        Method objMethod = classTarget.getMethod(methodName, par);
        if (objMethod.isAnnotationPresent(PostMapping.class)) 
            PostMapping rm2 = objMethod.getAnnotation(PostMapping.class);
            url += rm2.value()[0];
         else if (objMethod.isAnnotationPresent(GetMapping.class)) 
            GetMapping rm3 = objMethod.getAnnotation(GetMapping.class);
            url += rm3.value()[0];
         else if (objMethod.isAnnotationPresent(DeleteMapping.class)) 
            DeleteMapping rm4 = objMethod.getAnnotation(DeleteMapping.class);
            url += rm4.value()[0];
         else if (objMethod.isAnnotationPresent(PutMapping.class)) 
            PutMapping rm5 = objMethod.getAnnotation(PutMapping.class);
            url += rm5.value()[0];
         else if (objMethod.isAnnotationPresent(RequestMapping.class)) 
            RequestMapping rm6 = objMethod.getAnnotation(RequestMapping.class);
            url += rm6.value()[0];
        
        System.out.println(url);
        // 不检查的url
        if ("/ows/file/play/name".equals(url)) 
            return;
        
        if ("/ows/user/listRole".equals(url)) 
            return;
        
        if (url.startsWith("/approve")) 
            return;
        
        if (url.startsWith("/feginAsp")) 
            return;
        
        if (url.startsWith("/api/urgnetProblem")) 
            return;
        
        if (url.contains("/problemThroughTrain")) 
            return;
        
        if (url.contains("/clientIndex")) 
            return;
        
        if (url.contains("/policystu/data")) 
            return;
        
        if (AppContext.getCurrentUser() == null) 
            throw new BadRequestException("未登录访问[" + url + "]");
        
        String agentId = AppContext.getCurrentUser().getUserAgentId();
        //判断用户是否有相关的二级菜单
        Set<String> secondMenus = AppContext.getCurrentUser().getSecondMenus();
        List<String> matchPids = null;
        for (String ks : URL_PID_MAPPING.keySet()) 
            if (url.startsWith(ks)) 
                matchPids = URL_PID_MAPPING.get(ks);
                break;
            
        
        // 未配置的api 忽略
        if (matchPids == null || matchPids.size() == 0) 
//            throw new BadRequestException(agentId + " 未配置的api [" + url + "]");
            return;
        
        boolean isMatch = false;
        for (String matchPid : matchPids) 
            if (secondMenus.contains(matchPid)) 
                isMatch = true;
                break;
            
        
        if (!isMatch) 
            throw new BadRequestException(agentId + " 无权限访问! [" + url + "]");
        
    
public class XSSFilter implements Filter 
    @Override
    public void init(FilterConfig filterConfig) throws ServletException 
    

    @Override
    public void destroy() 
    

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException 
        chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request), response);
    

public class XSSRequestWrapper extends HttpServletRequestWrapper 
    public XSSRequestWrapper(HttpServletRequest servletRequest) 
        super(servletRequest);
    

    @Override
    public String[] getParameterValues(String parameter) 
        String[] values = super.getParameterValues(parameter);
        if (values == null) 
            return null;
        
        int count = values.length;
        String[] encodedValues = new String[count];
        for (int i = 0; i < count; i++) 
            encodedValues[i] = stripXSS(values[i]);
        
        return encodedValues;
    

    @Override
    public String getParameter(String parameter) 
        String value = super.getParameter(parameter);
        return stripXSS(value);
    

    @Override
    public String getHeader(String name) 
        String value = super.getHeader(name);
        return stripXSS(value);
    

    // 对值进行html实体编码
    private String stripXSS(String value) 
        if (value != null) 
            value = HtmlUtils.htmlEscape(value);
        
        return value;
    

以上是关于全局权限控制的主要内容,如果未能解决你的问题,请参考以下文章

全局权限控制

vue3全局自定义指令实现按钮权限控制

DRF 版本认证权限限制解析器和渲染器

DRF 版本认证权限限制解析器和渲染器

net core体系-web应用程序-4asp.net core2.0 项目实战-13基于OnActionExecuting全局过滤器,页面操作权限过滤控制到按钮级

Jenkins的权限控制