Zuul配置OAuth资源服务器

Zuul配置OAuth资源服务器
1.分析
我们都知道Zuul是网关,所有的请求都要经过这里,再到指定的资源服务器,但是经过Zuul之后,你携带的token Zuul是不会携带着去访问 指定的资源服务器的,所以会造成一个你携带了token但是还是显示你没有认证
接下来我将展示我的代码,并解释其中的原理
2.
ResourceServerConfig.java
因为所有请求都要经过网关Zuul,所以这里OAuth配置要配置所有的资源服务器以及认证服务器的资源配置,和安全配置
@Configuration
public class ResourceServerConfig {

    @Autowired
    private TokenStore tokenStore;
    @Autowired
    private AuthExceptionEntryPoint authExceptionEntryPoint;


    //认证服务器的配置
    @Configuration
    @EnableResourceServer
    public class AuthorizationServer extends ResourceServerConfigurerAdapter{

        public String RESOURCE_ID = "zuul";

        //资源服务安全配置
        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources
                    .tokenStore(tokenStore)//令牌存储验证服务,让资源服务自己验证token
                    .resourceId(RESOURCE_ID)//资源ID
                    .stateless(true);//会话机制stateless开启
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests()
                    .antMatchers("/uaa/**")
                    .permitAll();
        }
    }

    //emplyee资源服务器的配置
    @Configuration
    @EnableResourceServer
    public class ResourceServer extends ResourceServerConfigurerAdapter{

        public String RESOURCE_ID = "employee";

        //资源服务安全配置
        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources
                    .tokenStore(tokenStore)//令牌存储验证服务,让资源服务自己验证token
                    .resourceId(RESOURCE_ID)//资源ID
                    .authenticationEntryPoint(authExceptionEntryPoint)//配置token异常的处理
                    .stateless(true);//会话机制stateless开启
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests()
                    .antMatchers("/employee/**").authenticated();
        }
    }

    /**
     *  ......到时加其他资源服务器 再配置
     */

}
AuthFilter.java
当请求携带token经过认证 并放入认证对象中,经过此过滤器,把认证对象的信息明文放入转发给资源服务器请求的请求头中
public class AuthFilter extends ZuulFilter {

    //filter类型 随便写但是要有意义的
    @Override
    public String filterType() {
        return "pre";
    }

    //数值越小 越优先
    @Override
    public int filterOrder() {
        return 0;
    }

    //是否过滤
    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {

        RequestContext context = RequestContext.getCurrentContext();
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        //如果不是 OAuth2Authentication 认证对象 则返回null
        if(!(authentication instanceof OAuth2Authentication)){
            return null;
        }

        OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) authentication;
        Authentication userAuthentication = oAuth2Authentication.getUserAuthentication();
        //取出用户名
        String principal = userAuthentication.getName();

        /**
         * 组装明文token,转发给微服务,放入header,名称为json-token
         */
        final List<String> authorities = new ArrayList<>();
        userAuthentication.getAuthorities().stream().forEach(s -> authorities.add(((GrantedAuthority)s).getAuthority()));
        OAuth2Request oAuth2Request = oAuth2Authentication.getOAuth2Request();
        Map<String, String> requestParameters = oAuth2Request.getRequestParameters();
        Map<String, Object> jsonToken = new HashMap<>(requestParameters);

        if (userAuthentication != null) {
            jsonToken.put("principal",principal);
            jsonToken.put("authroities",authorities);
        }
        try {
            String jsonStrToken = new ObjectMapper().writeValueAsString(jsonToken);
            context.addZuulRequestHeader("json-token", Base64.getEncoder().encodeToString(jsonStrToken.getBytes()));
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }
}
ZuulConfig.java
因为所有请求都要经过网关Zuul,在这里配置支持跨域请求的配置以及,配置上面的过滤器
@Configuration
public class ZuulConfig {

    @Bean
    public AuthFilter authFilter(){
        return new AuthFilter();
    }

    //支持跨域请求配置
    @Bean
    public FilterRegistrationBean filterRegistrationBean(){
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");

        source.registerCorsConfiguration("/**",corsConfiguration);
        CorsFilter corsFilter = new CorsFilter(source);
        FilterRegistrationBean<Filter> filterFilterRegistrationBean = new FilterRegistrationBean<>(corsFilter);
        filterFilterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return filterFilterRegistrationBean;
    }

}
WebSecurityConfig.java
这里将放行所有请求,把认证的功能交由资源服务器的认证
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/**").permitAll()
                .and()
                .csrf().disable()
                .cors().disable();
    }
}
TokenStoreConfig.java
配置token存储策略和token转换器,以便Zuul将请求头中的token解析出来放入认证对象中
@Configuration
public class TokenStoreConfig {

    private String SIGNING_KEY = "lzj";

    @Bean
    public TokenStore tokenStore(){
        //JWT令牌存储方案
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter(){
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(SIGNING_KEY);
        return converter;
    }

}
application.yml
添加以下配置信息到配置文件中
#配置下zuul的超时时间,因zuul启用了ribbon的负载均衡,还需要设置ribbon的超时时间,注意ribbon的超时时间要小于zuul超时时间 。
zuul:
  host:
    connect-timeout-millis: 15000 #HTTP连接超时要比Hystrix的大
    socket-timeout-millis: 60000   #socket超时
  #忽略框架默认的服务映射路径
  ignored-services: '*'
  #不忽略任何头部信息,所有header都转发到下游的资源服务器
  sensitive-headers: '*'
  retryable: true #zuul的重试机制开启 需要spring-retry依赖
  add-host-header: true #加上主机头信息
  routes:
    oauth-server:
      serviceId: oauth-server
      path: /uaa/**
    employee:
      serviceId: employee
      path: /employee/**


ribbon:
  ReadTimeout: 10000
  ConnectTimeout: 10000
可以看到我的配置文件配置了retryable 重试机制,这需要引入一个依赖
		<dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>
如果没有配置重新机制,在如果Zuul访问的资源服务器宕机,他不会触发Hystrix,而是返回错误页面,这不是我们想看到的,这时候你配置了重试机制,他就会重新连接一次,连接失败换其他的资源服务。
到此你还需要到资源服务器配置一个过滤器
这个过滤器的作用是,第一个过滤请求,把请求中请求头的明文认证信息放入到认证对象中,以完成资源服务器的认证
TokenAuthenticationFilter.java
public class TokenAuthenticationFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        String token = httpServletRequest.getHeader("json-token");
        if(token != null){
            String jsonStrToken = Base64.getDecoder().decode(token).toString();
            Map map = new ObjectMapper().readValue(jsonStrToken, Map.class);
            //用户名
            String principal = (String) map.get("principal");
            //用户权限
            List<String> authroities = (List<String>) map.get("authroities");
            String[] authroitiesArray = authroities.toArray(new String[authroities.size()]);
            //创建authenticationtoken对象
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken
                    = new UsernamePasswordAuthenticationToken(principal, null, AuthorityUtils.createAuthorityList(authroitiesArray));
            usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));

            //将对象填充到安全上下文中
            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        }
        //放行过滤器
        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }
}
大功告成!!!!
测试

在这里插入图片描述






一键查询淘宝/拼多多内部优惠券,每日大额外卖红包,购物省钱的宝藏工具
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot Zuul是一个在微服务架构中用于网关路由和过滤的组件。它允许我们通过定义动态路由配置来控制请求的转发。 要在Spring Boot Zuul配置动态路由转发,我们需要执行以下几个步骤: 1. 添加Zuul依赖:在pom.xml文件中添加Zuul的依赖,以便我们可以使用它的功能。 2. 创建Zuul配置类:创建一个Java类来配置Zuul。在该类上添加`@EnableZuulProxy`注解,以启用Zuul代理和路由功能。可以使用`@Configuration`注解标记该类为配置类。 3. 配置动态路由:在配置类中,使用`@ConfigurationProperties`注解来加载动态路由的配置,如下所示: ```java @ConfigurationProperties("zuul") public class ZuulConfig { private List<Route> routes; // Getters and setters public static class Route { private String path; private String url; private boolean stripPrefix; // Getters and setters } } ``` 在`ZuulConfig`类中,我们定义了一个内部类`Route`,它表示一条动态路由。我们需要配置每个路由的`path`、`url`和`stripPrefix`属性。 4. 启用动态路由配置:在配置类中添加`@Bean`注解来创建一个`ZuulConfiguration` bean,并使用它来启用动态路由配置。代码如下所示: ```java @Configuration public class ZuulConfig { // ... @Bean public ZuulConfiguration zuulConfiguration() { ZuulConfiguration zuulConfiguration = new ZuulConfiguration(); zuulConfiguration.setRoutes(this.routes); return zuulConfiguration; } } ``` 在`zuulConfiguration()`方法中,我们创建了一个`ZuulConfiguration`对象,并将动态路由配置赋值给它。 5. 测试路由转发:完成以上步骤后,我们可以通过访问定义的动态路由来测试路由转发是否正常工作。根据配置的`path`属性,Zuul将会把请求转发到相应的`url`。 这是使用Spring Boot Zuul配置动态路由转发的基本步骤。通过配置动态路由,我们可以动态地将请求转发到不同的后端服务,并根据路由规则对请求进行过滤和重定向。这使得网关服务在微服务架构中起到关键的作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值