OAuth2.0-4整合网关
阅读原文时间:2023年07月08日阅读: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中