I am building Rest api using microservice architecture. I have multiple apis for user that we have made into multiple projects. I have everything else ready except I am not able to map the user facing url to the application url in zuul.
The user facing url is : user/v1/accountholders/{id}/cards and the actual url for my application is /user-cards/v1/accountholders/{id}/cards.
Here id is the path variable. Below are other similar api url so if there is a way to configure them generically in zuul. Also the context root of the application url is also the project name in Eureka.
Other similar urls are:
client side:- /user/v1/accountholders/{id}/cards/{cardid}
application:- /user-cards/v1/accountholders/{id}/cards/{cardid}
client side:- /user/v1/accountholders
application:- /user-cardholder/v1/accountholder
client side:- /user/v1/accountholders
application:- /user-cardholder/v1/accountholder
client side:- /user/v1/accountholders/{id}
application:- /user-cardholder/v1/accountholders/{id}
client side:- /user/v1/accountholders/{id}/accounts
application:- /user-accounts/v1/accountholders/{id}/accounts
client side:- /user/v1/accountholders/{id}/accounts/{accid}
application:- /user-accounts/v1/accountholders/{id}/accounts/{accid}
Need some help to set this up in the properties or yml file for zuul. I havent been able to make any progress with the mapping stuff yet. Any inputs will be helpful.
SOLVED:-
After getting the input from #Daniel (which is the accepted answer)This is what i used in zuul config:-
zuul:
routes:
User-Cards:
path: /user/v1/accountholders/*/cards/**
url: http://desktop-uvkv1ed:9999/user-cards/v1/accountholders
User-Transactions1:
path: /user/v1/accountholders/*/transactions
url: http://desktop-uvkv1ed:5555/user-transactions/v1/accountholders
service-id: User-Transactions
User-Transactions2:
path: /user/v1/accountholders/*/accounts/*/transactions
url: http://desktop-uvkv1ed:5555/user-transactions/v1/accountholders
service-id: User-Transactions
User-Accounts:
path: /user/v1/accountholders/*/accounts/**
url: http://desktop-uvkv1ed:7777/user-accounts/v1/accountholders
User-Cardholders:
path: /user/v1/accountholders/**
url: http://desktop-uvkv1ed:8888/user-cardholders/v1/accountholders
It is possible to achieve what you are trying to do by giving the correct Zuul config. Lets assume you have the user-cardholder service running on port 8081 and the user-account service on 8082 so that you can successfully answer requests going against:
http://localhost:8081/user-cardholder/accountholders/{id}
http://localhost:8082/user-account/accountholders/{id}/accounts/{accid}
If this is working then you can achive what you are trying for these two services by using the following zuul config:
zuul:
routes:
cardholder:
path: /user/accountholders/*
url: http://localhost:8081/user-cardholder/accountholders/
account:
path: /user/accountholders/*/accounts/**
url: http://localhost:8082/user-accounts/accountholders/
Unfortunately you will also have to add more configs – even when they go against the same backend service – due to the fact that internal and external urls are differing. Otherwise you could just add the option stripPrefix: false and use the same internally as externally.
Related
how to set private endpoint in zuul?
env: spring, zuul
i'm using
zuul:
routes:
abc:
path: /abc/**
sensitive-headers:
url: http://abc.api.develop.com
in abc service, i want to make private /abc/xyz/1/test.
only it has to be work, when i request directly to http://abc.api.develop.com/xyz/1/test in server. not https://develop.com/abc/xyz/1/test by gateway.
/abc/1, /abc/1/public, /abc/xyz/2/good etc have to be public.
so only one path(/abc/xyz/1/test) is private endpoint.
how to set this?
can anyone help me please?
or any hint?
is zuul setting or is spring security setting?
how to block this specific path?
I used ignoredPatterns: /abc/xyz/*/good.
I have a Spring gateway microservices with this mapping:
- id: advertisementService4
uri: lb://advertisementService
predicates:
- Path=/public/breeds/**
filters:
- RewritePath=/public/breeds/(?<segment>/?.*), /v1/public/breeds/$\{segment}
If I make a call with Postman to this url: http://192.168.99.1:8050/public/breeds/500, the gateWay service solves the mapping and build the new url in the correct way (to /v1/public/breeds/500):
But if I call to this url http://192.168.99.1:8050/public/breeds?petType=Dog, the gateWay service chooses the correct mapping, but it builds the url in a incorrect way:
The gateWay service builds http://7a32a826ec7a:8070/public/breeds?petType=Dog instead of http://7a32a826ec7a:8070/v1/public/breeds?petType=Dog (with v1 in the URL)
I don't understand why. Could you help me please?
I fixed it changing the RewritePath:
from RewritePath=/public/breeds/(?/?.), /v1/public/breeds/${segment}
to RewritePath=/(?/?.), /v1/${segment}
I am encountering a very peculiar problem in spring cloud gateway. Every alternate request returns a 404. This happens across all services I've configured in the api-gateway without exception. I don't even know where to start to debug this problem.
Here's my application.yml file for common config.
server:
port: 8080
ssl:
enabled: true
key-store: classpath:keystore.p12
key-store-password: password
key-store-type: pkcs12
key-alias: tomcat
security:
require-ssl=true:
logging:
level:
org:
springframework:
cloud.gateway: DEBUG
http.server.reactive: DEBUG
web.reactive: DEBUG
spring:
application:
name: api-gateway
cloud:
gateway:
httpclient:
ssl:
useInsecureTrustManager: true
Here's my java config file
#EnableWebFluxSecurity
public class SecurityConfig {
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http,
ReactiveClientRegistrationRepository clientRegistrationRepository) {
// Authenticate through configured OpenID Provider
http.oauth2Login();
// Also logout at the OpenID Connect provider
http.logout(logout -> logout.logoutSuccessHandler(new OidcClientInitiatedServerLogoutSuccessHandler(
clientRegistrationRepository)));
// Require authentication for all requests
http.authorizeExchange().anyExchange().authenticated();
// Allow showing /home within a frame
http.headers().frameOptions().mode(Mode.SAMEORIGIN);
// Disable CSRF in the gateway to prevent conflicts with proxied service CSRF
http.csrf().disable();
return http.build();
}
}
Here's the spring profile specific config file that gets loaded on top of the common application.yml file.
spring:
security:
oauth2:
client:
provider:
keycloak:
issuerUri: http://localhost:9080/auth/realms/mylocal
userNameAttribute: preferred_username
registration:
keycloak:
clientId: api-gateway-client
clientSecret: abcdefgh-ijkl-mnop-qrst-uvwxyz5d6a9
cloud:
gateway:
default-filters:
- TokenRelay
routes:
- id: news
uri: http://localhost:8082/news
predicates:
- Path= /news/**
- id: customers
uri: http://localhost:8083/customers
predicates:
- Path= /boards/**
- id: search
uri: http://localhost:8085/search
predicates:
- Path= /search/**
Hey i got the issue recently too, I figure out that it was the load balancing the issue. Make sure that your spring.application.name of the microservice that you try to contact are all in capital letter (EXAMPLE) especially if you use Eureka. (hope it helps)
I had a similar issue. The reason was in registration of several services under the same application name in my Eureka server. Just like this:
Eureka instances screenshot
Those are completely different services, but they are registered under one application name. So when a request is made through load balancer, the latter tries to use both of the service urls. One service is able to serve request correctly, but another one may know nothing about the requested path, that is why 404 is returned.
Check if there are two or more microservices using the same spring.application.name and registered with eureka.
I know it's an old question... But might help future readers.
hey, here is the simplest solution I found for myself, in the browser
url, instead of 'localhost', give your system's name.
ex:
http://hp:8083/SERVICE-NAME/customers/**
also make sure to name all your spring application in uppercase.
Hello I tried to make routing with zuul work I looked at the docs and read this part.
application.yml.
zuul:
routes:
users: /myusers/**
This means that http calls to "/myusers" get forwarded to the "users" service (for example "/myusers/101" is forwarded to "/101").
https://cloud.spring.io/spring-cloud-netflix/multi/multi__router_and_filter_zuul.html
My application.yml looks like this
zuul:
routes:
home:
path: /home/**
serviceId: SKELETONPAGE
stripPrefix: false
The /home path won't take me to the skeletonpage service and this service will instead be mapped to /skeletonpage. Am I filling in the properties wrong or is there another thing that I may forgot?
Please note that stripPrefix: false means that your request to /home/index.html will result in request being forwarded to SKELETONPAGE/home/index.html.
With stripPrefix: true it will route to SKELETONPAGE/index.html
I have created a Single Page Application using the Spring Tutorial for making one with AngularJS and OAuth and such found here:
https://spring.io/guides/tutorials/spring-security-and-angular-js/#_multiple_ui_applications_and_a_gateway_single_page_application_with_spring_and_angular_js_part_vi
This is the application.yml files for the SPA application:
security:
user:
password: none
oauth2:
client:
accessTokenUri: localhost:7777/uaa/oauth/token
userAuthorizationUri: localhost:7777/uaa/oauth/authorize
clientId: acme
clientSecret: acmesecret
resource:
user-info-uri: localhost:7777/uaa/user
zuul:
routes:
resource:
path: /resource/**
url: localhost:9000/resource
user:
path: /user/**
url: localhost:7777/uaa/user
eureka:
client:
serviceUrl:
defaultZone: ${vcap.services.eureka-service.credentials.uri:127.0.0.1:8761}/eureka/
---
spring:
profiles: cloud
eureka:
instance:
hostname: ${APPLICATION_DOMAIN}
nonSecurePort: 80
I want to know how I would change the zuul routes and the user-info-uri so that I don't have to specify the urls and all this can be done by using the service-id. I looked at the tutorial for using eureka here:
https://spring.io/blog/2015/01/20/microservice-registration-and-discovery-with-spring-cloud-and-netflix-s-eureka
but I don't quite understand how I can achieve my goal without adding all the java to my code, because the basic eureka server already seems to register all my services.
Had issue with using eureka service id, userInfoUri used to throw UnknownHost Exception all the time, #LoadBallanced restTemplate did not solve my issue, solution was to set prefer-token-info to false ( if true - no load ballancing for oauth )
security.oauth2.resource.service-id={Service ID as at eureka server registered}
security.oauth2.resource.userInfoUri= http://${security.oauth2.resource.service-id}/user/me
security.oauth2.resource.loadBalanced=true
security.oauth2.resource.prefer-token-info=false
no port number needed if service ID used , but needed if ip or host used
If I do understand your question correct you can just use the config file in this pattern:
zuul:
routes:
<service_id>:
path: /path/**
For example (if your oauth-service is registered as auth):
zuul:
routes:
auth:
path: /user/**
Zuul will leverage Eureka and find the endpoints for the services. In addition to that it will provide client-side load-balancing.