前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >第十四节 springcould zuul边缘路由的使用

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

作者头像
用户1418372
发布2018-10-15 11:30:39
9880
发布2018-10-15 11:30:39
举报

本微服务中使用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、以及其他业务服务

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.10.14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 本微服务中使用zuul 服务网关作为边缘路由,在oauth2中同时它本身也是资源服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档