Feign客户端对Url引发未经授权的异常,其中不需要身份验证



我关注过这个博客,并创建了一些微服务:Eureka服务器、Auth服务、Zuul服务、Gallery服务、Image服务。从库服务中,我想使用Feign-Client调用auth-service APIurl不需要身份验证,但客户端抛出FeignException$Unauthorized我使用JWT令牌进行身份验证。

//AuthServerProxy.java
@FeignClient(name = "auth-service")
@RibbonClient(name = "auth-service")
public interface AuthServiceProxy {
@PostMapping("/auth/authenticate")
public ResponseEntity<?> authenticate(@RequestBody UserEntity userEntity);
@GetMapping("/auth/register")
public String test();
}

控制器-画廊服务

@Autowired
AuthServiceProxy authServiceProxy;
@GetMapping("/test")
public String test(){
UserEntity userEntity = new UserEntity();
userEntity.setUsername("admin");
userEntity.setPassword("admin");
ResponseEntity<?> responseEntity = authServiceProxy.authenticate(userEntity);
System.out.println(responseEntity.getStatusCode());
return responseEntity.toString();
}
@GetMapping("/test/str")
public String testStr(){
return authServiceProxy.test();
}

安全配置-ZuulServer,身份验证服务

.antMatchers(HttpMethod.POST, "/auth/authenticate").permitAll()

这是错误日志

ERROR 1123 --- [nio-8100-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is feign.FeignException$Unauthorized: status 401 reading AuthServiceProxy#authenticate(UserEntity)] with root cause
feign.FeignException$Unauthorized: status 401 reading AuthServiceProxy#authenticate(UserEntity)
at feign.FeignException.errorStatus(FeignException.java:94) ~[feign-core-10.2.3.jar:na]
at feign.FeignException.errorStatus(FeignException.java:86) ~[feign-core-10.2.3.jar:na]
at feign.codec.ErrorDecoder$Default.decode(ErrorDecoder.java:93) ~[feign-core-10.2.3.jar:na]
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:149) ~[feign-core-10.2.3.jar:na]
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:78) ~[feign-core-10.2.3.jar:na]
at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103) ~[feign-core-10.2.3.jar:na]
at com.sun.proxy.$Proxy101.authenticate(Unknown Source) ~[na:na]
at com.test.gallery.Controller.test(Controller.java:47) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_201]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_201]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_201]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_201]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
...

非常感谢您的帮助。TIA-

Feign不知道应该传递给目标服务的授权。不幸的是,你需要自己处理。下面是一个可以帮助的java类

@Component
public class FeignClientInterceptor implements RequestInterceptor {
private static final String AUTHORIZATION_HEADER = "Authorization";
private static final String BEARER_TOKEN_TYPE = "Bearer";


@Override
public void apply(RequestTemplate template) {
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
if (authentication != null && authentication.getDetails() instanceof OAuth2AuthenticationDetails) {
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
template.header(AUTHORIZATION_HEADER, String.format("%s %s", BEARER_TOKEN_TYPE, details.getTokenValue()));
}
}

看起来Authentication标头没有通过FeignClient

尝试添加此配置:

@Bean
public RequestInterceptor requestInterceptor() {
return requestTemplate -> {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getDetails() instanceof OAuth2AuthenticationDetails) {
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
requestTemplate.header(HttpHeaders.AUTHORIZATION, String.format("Bearer %s", details.getTokenValue()));
}
};
}

听起来问题可能是您的Auth服务没有连接@EnableResourceServer。

如果没有该注释,任何不属于spring安全包的端点(例如/oauth/token、/oauth/check_token(都将自动需要授权。

此外,您可能需要添加类似的ResourceServerConfigurerAdapter,以确保资源端点配置为允许所有类似的操作:

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private final TokenStore tokenStore;
public ResourceServerConfig(TokenStore tokenStore) {
this.tokenStore = tokenStore;
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.POST).permitAll()
.and()
.logout().disable()
.csrf().disable();
}
}

*******编辑*********

如果你能够从浏览器中的请求中获得ok响应,但不能假装,那么你的问题很可能是你的feign客户端没有指向正确的端点。通常情况下,你会期望出现404错误,但由于API是安全的,你会得到401,因为它甚至不允许你知道什么是有效的端点,除非你通过了身份验证或它是一个不安全的端点

如果您的AuthServiceProxy外籍客户端使用zuul服务器而不是身份验证服务,那么您可以将日志记录添加到zuul筛选器中,以查看成功和不成功的请求是什么样子的。从那里进行必要的更改,使您的代理请求与您从浏览器发出的请求相匹配,您应该可以使用

相关内容

最新更新