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中