服务之间的资源权限校验

四路:- 这个操作是否应该在网关来做?  服务之间的调用权限还是适合在服务自身处理

a: 创建拦截器1,用于服务之间的请求校验

b: 创建拦截器2,用于restTemplate请求的校验

1- 编写拦截器1

package spring.cloud.common.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.alibaba.fastjson.JSON;
import spring.cloud.common.context.UserContextHolder;
import spring.cloud.common.util.UserPermissionUtil;
import spring.cloud.common.vo.User;

public class UserContextInterceptor extends HandlerInterceptorAdapter {

    private static final Logger log = LoggerFactory.getLogger(UserContextInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse respone, Object arg2) throws Exception {
        User user = getUser(request);
        // TODO 日常测试先关闭服务间的资源权限校验
//        UserPermissionUtil.permission(user);
//        if(!UserPermissionUtil.verify(user,request)) {
//            respone.setHeader("Content-Type", "application/json");
//            String jsonstr = JSON.toJSONString("no permisson access service, please check");
//            respone.getWriter().write(jsonstr);
//            respone.getWriter().flush();
//            respone.getWriter().close();
//            throw new PermissionException("no permisson access service, please check");
//        }
        UserContextHolder.set(user);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse respone, Object arg2, ModelAndView arg3)
            throws Exception {
        // DOING NOTHING
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse respone, Object arg2, Exception arg3)
            throws Exception {
        UserContextHolder.shutdown();
    }

    private User getUser(HttpServletRequest request){
        String userid = request.getHeader("x-user-id");
        String username = request.getHeader("x-user-name");
        User user = new User();
        user.setUserId(userid);
        user.setUserName(username);
        return user;
    }

    static class PermissionException extends RuntimeException {
        private static final long serialVersionUID = 1L;
        public PermissionException(String msg) {
            super(msg);
        }
    }
}

2 - 编写校验工具类

package spring.cloud.common.util;

import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.util.StringUtils;
import spring.cloud.common.vo.User;

public class UserPermissionUtil {

    /**
     * 模拟权限校验, 可以根据自己项目需要定制不同的策略,如查询数据库获取具体的菜单url或者角色等等.
     * @param user
     */
    public static boolean verify(User user, HttpServletRequest request){
        // TODO 从请求头获取用户信息,再查询DB判断该用户是否具有该服务或者该服务下某个url的权限
        String url = request.getHeader("x-user-serviceName");
        if(StringUtils.isEmpty(user)) {
            return false;
        }else {
            List<String> str = user.getAllowPermissionService();
            for (String permissionService : str) {
                if(url.equalsIgnoreCase(permissionService)) {
                    return true;
                }
            }
            return false;
        }
    }

    /**
     * 模拟权限赋值, 可以根据自己项目需要定制不同的策略,如查询数据库获取具体的菜单url或者角色等等.
     * 该方法应该放到业务层,通过访问DB获取权限资源列表
     * @param user
     */
    public static void permission(User user){
        if(user.getUserName().equals("admin")) {
            List allowPermissionService = new ArrayList();
            // TODO 查询DB资源权限数据
            allowPermissionService.add("client-service");
            allowPermissionService.add("provider-service");
            allowPermissionService.add("SPRING-CLOUD-FEIGN");
            user.setAllowPermissionService(allowPermissionService);
        }else if(user.getUserName().equals("spring")) {
            List allowPermissionService = new ArrayList();
            allowPermissionService.add("client-service");
            user.setAllowPermissionService(allowPermissionService);
        } else {
            List allowPermissionService = new ArrayList();
            user.setAllowPermissionService(allowPermissionService);
        }
    }

}

3- 编写上下文持有对象

package spring.cloud.common.context;

import spring.cloud.common.vo.User;

public class UserContextHolder {
    public static ThreadLocal<User> context = new ThreadLocal<>();
    public static User currentUser() {
        return context.get();
    }
    public static void set(User user) {
        context.set(user);
    }
    public static void shutdown() {
        context.remove();
    }
}

4- 编写拦截器2

package spring.cloud.common.interceptor;

import java.io.IOException;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import spring.cloud.common.context.UserContextHolder;
import spring.cloud.common.vo.User;

public class RestTemplateUserContextInterceptor implements ClientHttpRequestInterceptor {

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
            throws IOException {
        User user = UserContextHolder.currentUser();
        request.getHeaders().add("x-user-id",user.getUserId());
        request.getHeaders().add("x-user-name",user.getUserName());
        request.getHeaders().add("x-user-serviceName",request.getURI().getHost());
        return execution.execute(request, body);
    }
}

5 将2个拦截器注入IOC容器

package spring.cloud.common.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import spring.cloud.common.interceptor.RestTemplateUserContextInterceptor;
import spring.cloud.common.interceptor.UserContextInterceptor;

/**
 * 详见 https://www.cnblogs.com/duanxz/p/4875153.html
 */
@Configuration
@EnableWebMvc
public class CommonConfiguration implements WebMvcConfigurer {

    /**
     * 请求拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        System.out.println("--------------UserContextInterceptor-------------");
        registry.addInterceptor(new UserContextInterceptor());
        //可以指定拦截器的路劲
        //registry.addInterceptor(new ThemeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
        //registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
    }

    /***
     * RestTemplate 拦截器,在发送请求前设置鉴权的用户上下文信息
     * @return
     */
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        System.out.println("--------------resttemplate-------------");
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getInterceptors().add(new RestTemplateUserContextInterceptor());
        return restTemplate;
    }

}
原文地址:https://www.cnblogs.com/domi22/p/10524124.html