OAuth2.0-4整合网关

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

.antMatchers("/**").access("#oauth2.hasScope('scope1')")
上面这行代码,只是控制大范围的访问权限,具体到方法级的访问 还得看permission

 

 

 以上教程代码顺序如下:

网关服务:

 

 

 

1.application.properties

#zuul不传递cookie和head信息
#方法1:这个设置是开启全局的cookie和head传递
zuul.sensitive-headers=

2.application.yml

server:
  port: 5001
spring:
  application:
    name: zuul
  cloud:
    client:
      ipAddress: 127.0.0.1
eureka:
  instance:
    prefer-ip-address: false
    instance-id: ${spring.cloud.client.ipAddress}:${server.port}
    hostname: ${spring.cloud.client.ipAddress}
  client:
    serviceUrl:
      #eurekaServers
      defaultZone: http://127.0.0.1:2001/eureka
zuul:
  routes:
    authorization_server: /uaa/**
    order_server: /order/**
    sensitive-headers:

3.网关资源服务:

/**
 * 网关资源类
 */
@Configuration
public class ResourceServerConfig {
    public static final String RESOURCE_ID="res1";


    //1 uaa认证授权服务资源 配置
    @Configuration
    @EnableResourceServer
    public class UAAServerConfig  extends ResourceServerConfigurerAdapter{
        @Autowired
        private TokenStore tokenStore;
        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources
                    //设置我这个resource的id
                    .resourceId(RESOURCE_ID)
                    .tokenStore(tokenStore)
                    //这个貌似是配置要不要把token信息记录在session中
                    .stateless(true);
        }
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers("/uaa/**").permitAll();//放行所有授权验证请求
        }
    }


    //2 order_server……等等微服务资源
    @Configuration
    @EnableResourceServer
    public class orderServerConfig  extends ResourceServerConfigurerAdapter{
        @Autowired
        private TokenStore tokenStore;
        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources
                    .resourceId(RESOURCE_ID)
                    .tokenStore(tokenStore)
                    .stateless(true);
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    //本项目所需要的授权范围,这个scope是写在auth服务的配置里的
                    .antMatchers("/order/**").access("#oauth2.hasScope('scope1')");
        }

    }


}
TokenConfig
@Configuration
public class TokenConfig {

    //配置如何把普通token转换成jwt token
    @Bean
    public JwtAccessTokenConverter tokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();

        //使用对称秘钥加密token,resource那边会用这个秘钥校验token
        converter.setSigningKey("uaa123");
        return converter;
    }

    //配置token的存储方法
    @Bean
    public TokenStore tokenStore() {
        //把用户信息都存储在token当中,相当于存储在客户端,性能好很多
        return new JwtTokenStore(tokenConverter());
    }
}

网关约束WebSecurityConfig

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/**").permitAll();

               // .and()
               // .formLogin()

              //  .and()
              //  .logout();
    }

    @Override
    @Bean
    public UserDetailsService userDetailsService() {
        /**
         * 基于内存创建用户
         */
        InMemoryUserDetailsManager manager=new InMemoryUserDetailsManager();

        manager.createUser(User.withUsername("zhangsan").password(passwordEncoder().encode("123")).authorities("admin").build());
        manager.createUser(User.withUsername("lisi").password(passwordEncoder().encode("123")).authorities("user").build());
        return manager;
    }
}
配置网关过滤器ZuulConfig、AuthFilter
/**
 * @Autor zhangjiawen
 * @Date: 2020/5/29 9:56
 */
@Configuration
public class ZuulConfig {

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

    @Bean
    public FilterRegistrationBean corsFilter(){
        final UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource();
        final CorsConfiguration config=new CorsConfiguration();
        config.setAllowCredentials(true);
        List<String> ruleList=new ArrayList<>();
        ruleList.add("*");
        config.setAllowedOrigins(ruleList);
        config.setAllowedHeaders(ruleList);
        config.setAllowedMethods(ruleList);
        config.setMaxAge(1800L);
        source.registerCorsConfiguration("/**",config);
        CorsFilter corsFilter=new CorsFilter(source);
        FilterRegistrationBean bean=new FilterRegistrationBean(corsFilter);
        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return bean;

    }
}
@Slf4j
public class AuthFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return "pre";//表示请求之前拦截
    }

    @Override
    public int filterOrder() {
        return -1;
    }

    @Override
    public boolean shouldFilter() {
        return true;//如果想要过滤器生效必须改成true
    }

    /**
     * 转发解析token
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        //1获取当前用户身份信息
        RequestContext ctx=RequestContext.getCurrentContext();
            //从上下文拿到身份对象
        Authentication authentication= SecurityContextHolder.getContext().getAuthentication();
        if(!(authentication instanceof OAuth2Authentication)){
            log.error("-----!(authentication instanceof OAuth2Authentication)");
            return null;//如果不是oauth2.0格式的对象 直接返回;
        }
        OAuth2Authentication oAuth2Authentication=(OAuth2Authentication) authentication;
        Authentication userAuthentication = oAuth2Authentication.getUserAuthentication();
        //取出用户身份
        String principal = userAuthentication.getName();
        //2获取当前用户权限信息
        List<String> authorities=new ArrayList<>();
            //采用stream流的方式遍历
        userAuthentication.getAuthorities().stream().forEach(c-> authorities.add(c.getAuthority()));
            //将原请求参数重新放回
        OAuth2Request oAuth2Request = oAuth2Authentication.getOAuth2Request();
        Map<String, String> requestParameters = oAuth2Request.getRequestParameters();
        Map<String, Object> jsonToken =new HashMap<>(requestParameters);
        //3把用户身份权限信息放入json,存入http的header中
        if(userAuthentication!=null){
            jsonToken.put("principal",principal);
            jsonToken.put("authorities",authorities);
        }

        ctx.addZuulRequestHeader("json-token", Base64.encode(JSON.toJSONString(jsonToken)));
        //4转发给微服务



        return null;
    }
}


授权服务uaa:

 

 

资源order服务:

 

 用户权限过滤器TokenAuthenticationFilter

/
 * @Autor zhangjiawen
 * @Date: 2020/5/29 10:16
 */
@Component
public class TokenAuthenticationFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //解析出头中的token
        String token = request.getHeader("json-token");
        if(!StringUtils.isEmpty(token)){
            String json= Base64.decodeStr(token);
            //将token转成json对象
            JSONObject jsonObject= JSON.parseObject(json);
            //获取身份信息
            String principal = jsonObject.getString("principal");
            UserDTO userDTO=new UserDTO();
            userDTO.setUsername(principal);

            //获取权限信息
            JSONArray authoritiesArray = jsonObject.getJSONArray("authorities");
            String[] authorities=authoritiesArray.toArray(new String[authoritiesArray.size()]);
            //将用户身份权限信息填充到用户token对象中
            UsernamePasswordAuthenticationToken authenticationToken
                    =new UsernamePasswordAuthenticationToken(userDTO,null, AuthorityUtils.createAuthorityList(authorities));
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            //将authenticationToken填充到安全上下文
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            filterChain.doFilter(request,response);

        }

    }
}

所有项目源码本人结合网友提供的代码整理了最后一部分 分布式的权限控制 参考:

https://gitee.com/jiawenzhang/Oauth-cloud

感谢哔哩哔哩提供的视频,地址:https://www.bilibili.com/video/BV1VE411h7aL?p=45

测试效果:

 

 

 

 

 

 

 

 

 

 

 将用户信息转成json对象放到username中

 

 

 

 

posted @ 2020-05-29 12:14  valar-dohaeris  阅读(1359)  评论(0编辑  收藏  举报