第十四节 springcould zuul边缘路由的使用

本微服务中使用zuul 服务网关作为边缘路由,在oauth2中同时它本身也是资源服务

  • 作为资源服务的部分配置和资源服务器api-server模块相似,同时也使用https,所以安全配置和security-server配置相似 具体参考如下:
  1. 生成证书keystore.jks,生成方式可参考: (安全服务模块中的证书生成部分)
  2. application.yml配置
#ssl配置
server:
    ssl:
        key-store: classpath:keystore.jks
        key-store-password: password
        key-password: password
    port: 8765
    compression:
        enabled: true
#oauth2 配置
security:
  oauth2:
    clientId: client
    clientSecret: password
    userAuthorizationUri: https://localhost:9001/oauth/authorize
    grant-type: password
    scope: apiAccess
    access-token-uri: https://localhost:9001/oauth/token
    resource:
      userInfoUri: https://localhost:9001/user
    authorization:
      checkTokenAccess: http://localhost:9001/oauth/check_token
  basic:
    enabled: false
# zuul路由配置
zuul:
    ignoredServices: "*"
    routes:
        restaurantapi:
            path: /api/**
            serviceId: api-service
            stripPrefix: true
        resource:
          path: /api/**
          url: http://localhost:9000
        user:
            path: /user/**
            url: https://localhost:9001/user
### 其他配置略。。。
  1. Security和配置
@Configuration
@EnableOAuth2Sso
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private BaseUserDetailService baseUserDetailService;
    //Spring Security 4.x -> 5.x  會無法直接注入AuthenticationManager,下面解決
    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
    /**
     * 用户验证
     * @param auth
     */
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(daoAuthenticationProvider());
        auth.userDetailsService(baseUserDetailService) .passwordEncoder(passwordEncoder());
    }
    /**
     * @param http
     * WebSecurityConfigurerAdapter和ResourceServerConfigurerAdapter二者是分工协作的
     * @throws Exception
     * WebSecurityConfigurerAdapter不拦截oauth要开放的资源
     */
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http    // 配置登陆页/login并允许访问
                .formLogin().permitAll()
                // 登出页
                .and().logout().logoutUrl("/logout").logoutSuccessUrl("/")
                // 其余所有请求全部需要鉴权认证
                .and().authorizeRequests().anyRequest().authenticated()
                // 由于使用的是JWT,我们这里不需要csrf
                .and().csrf().disable();
    }
    @Bean
    public DaoAuthenticationProvider daoAuthenticationProvider(){
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        // 设置userDetailsService
        provider.setUserDetailsService(baseUserDetailService);
        // 禁止隐藏用户未找到异常
        provider.setHideUserNotFoundExceptions(false);
        // 使用BCrypt(BCryptPasswordEncoder方法采用SHA-256 +随机盐+密钥)进行密码的hash
        provider.setPasswordEncoder(passwordEncoder());
        return provider;
    }
    @Bean
    public PasswordEncoder passwordEncoder(){
        return  new BCryptPasswordEncoder();
    }
}
  1. Resource配置
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    //spring.security.oauth2.client

//    @Autowired
//    private OAuth2ClientProperties oAuth2ClientProperties;
//    @Autowired
//    private AuthorizationServerProperties authorizationServerProperties;
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .exceptionHandling()
                .authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
                .and()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .httpBasic();
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.tokenServices(tokenServices());//.resourceId(SPARKLR_RESOURCE_ID);
    }

  @Bean
  public ResourceServerTokenServices tokenServices() {
        RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
//这里配置远程校验token的地址,(也可以使用其他方式,例如本地校验)
        remoteTokenServices.setCheckTokenEndpointUrl("https://security-service/oauth/check_token");
//为方便测试使用硬编码,要和security-server配置的相同(security服务会校验客户端信息)
        remoteTokenServices.setClientId("client");
        remoteTokenServices.setClientSecret("password");
      remoteTokenServices.setRestTemplate(restTemplate());
//使用默认令牌数据的存储
        remoteTokenServices.setAccessTokenConverter(accessTokenConverter());
        return remoteTokenServices;
    }

    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        //httpRequestFactory()
        RestTemplate restTemplate = new RestTemplate();
        List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters();
        for (HttpMessageConverter<?> converter : converters) {
            if (converter instanceof MappingJackson2HttpMessageConverter) {
                MappingJackson2HttpMessageConverter jsonConverter = (MappingJackson2HttpMessageConverter) converter;
                jsonConverter.setObjectMapper(new ObjectMapper());
                jsonConverter.setSupportedMediaTypes(ImmutableList.of(new MediaType("application", "json", MappingJackson2HttpMessageConverter.DEFAULT_CHARSET), new MediaType("text", "javascript", MappingJackson2HttpMessageConverter.DEFAULT_CHARSET)));
            }
        }
        return restTemplate;
    }
        @Bean
        public AccessTokenConverter accessTokenConverter() {
        return new DefaultAccessTokenConverter();
    }
}
  • 配置完基本已经可用,但作为边缘路由,它还具备其他很多有用的功能,比如可对请求前后过滤操作如下:
@Component
public class MyFilter extends ZuulFilter {
    private static Logger log = LoggerFactory.getLogger(MyFilter.class);
    @Override
    public String filterType() {
        // 前置过滤器
        return "pre";
    }
    @Override
    public int filterOrder() {
        // 优先级为0,数字越大,优先级越低
        return 0;
    }
    @Override
    public boolean shouldFilter() {
        // 是否执行该过滤器,此处为true,说明需要过滤
        return true;
    }

    //执行过程方法
    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
        Object accessToken = request.getHeader("Authorization");
//      Object accessToken = request.getParameter("token");
        if(accessToken == null) {
            log.warn("token is empty");
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            try {
                ctx.getResponse().getWriter().write("token is empty");
            }catch (Exception e){}
            return null;
        }
        log.info("ok");
        return null;
    }
}
  • 只需要继承ZuulFilter 覆写run方法作为要过滤执行的方法,filterType方法表示这个过滤器的类型(前置还是后置等。。)

其他具体配置及功能可参考源码zuul服务源码 需要说明需要启动本zuul项目,需要依赖eureka server、security-server、以及其他业务服务

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏乐沙弥的世界

Failed to upgrade Oracle Cluster Registry configuration(root.sh)

    最近在给客户基于Suse 11 sp3安装Oracle 10g RAC,在安装完clusterware执行/u01/app/crs/root.sh时收...

10310
来自专栏菩提树下的杨过

Spring Security笔记:使用数据库进行用户认证(form login using database)

在前一节,学习了如何自定义登录页,但是用户名、密码仍然是配置在xml中的,这样显然太非主流,本节将学习如何把用户名/密码/角色存储在db中,通过db来实现用户认...

21010
来自专栏闵开慧

hadoop错误代码查询

经常遇到的exception是:PipeMapRed.waitOutputThreads(): subprocess failed with code N "O...

47260
来自专栏Objective-C

iOS-安装和使用 CocoaPods

51270
来自专栏程序你好

Spring Security与OAuth2

Spring Security为基于j2ee的企业软件应用程序提供了全面的安全服务。它强大、灵活、可插。它不像代理服务器、防火墙、OS级别安全性、入侵检测系统或...

19030
来自专栏一个会写诗的程序员的博客

Circular view path [addKnowledge]: would dispatch back to the current handler URL

13710
来自专栏Netkiller

怎样制作RPM包

怎样制作RPM包 摘要 我在网上找RPM包的制作例子几乎都是C源码编译安装然后生成RPM包, 而我的程序不是C写的很多时候是脚本语言如Python, PHP 甚...

76960
来自专栏扎心了老铁

springboot kafka集成(实现producer和consumer)

本文介绍如何在springboot项目中集成kafka收发message。 1、先解决依赖 springboot相关的依赖我们就不提了,和kafka相关的只依赖...

97050
来自专栏芋道源码1024

注册中心 Eureka 源码解析 —— Eureka-Server 启动(二)之 EurekaBootStrap

本文主要基于 Eureka 1.8.X 版本 1. 概述 2. EurekaBootStrap 2.1 初始化 Eureka-Server 配置环境 2.2 初...

82440
来自专栏bboysoul

linux编译安装apache

wget http://mirrors.ustc.edu.cn/apache/httpd/httpd-2.4.25.tar.gz tar -zxvf http...

30930

扫码关注云+社区

领取腾讯云代金券