我試圖使用Spring Cloud的Zuul,Eureka和我自己的服務來實現微服務架構。我有多個具有UI和服務的服務,並且每個服務都可以使用x509安全性對用戶進行身份驗證。現在我試圖把祖魯放在這些服務之前。由於Zuul無法將客戶端證書轉發到後端,因此我認爲下一個最好的做法是在Zuul的前門驗證用戶,然後使用Spring Session在後端服務中複製其身份驗證狀態。我遵循Dave Syer的教程here,它幾乎可以工作,但不是第一次請求。這是我的基本設置:使用Spring Boot,Session和Redis創建會話時不會複製會話
- Zuul代理在它自己的應用程序集中路由到後端服務。是否已啓用Spring安全性來執行x509身份驗證。成功授權用戶。還有Spring會話與@EnableRedisHttpSession
- 後端服務也啓用彈簧安全。我已經嘗試在這裏啓用/禁用x509,但始終要求用戶對特定端點進行身份驗證。還使用Spring會話和@EnableRedisHttpSession。
如果清除所有會話並重新開始,並嘗試打代理,然後將其發送使用zuul服務器證書的請求傳遞給後臺。後端服務然後根據該用戶證書查找用戶,並認爲用戶是服務器,而不是在Zuul代理中進行身份驗證的用戶。如果您只是刷新頁面,那麼您突然成爲後端的正確用戶(在Zuul代理中進行身份驗證的用戶)。我檢查的方式是在後端控制器中打印Principal用戶。所以在第一次請求時,我看到服務器用戶,並在第二次請求時看到真實用戶。如果我在後臺禁用x509,在第一次請求時,我得到一個403,然後在刷新時,它讓我進入。
看起來好像會話沒有被快速複製到後端,所以當用戶在前端進行身份驗證時,在Zuul轉發請求之前,它並未將其發送到後端。
有沒有辦法保證會話在第一個請求(即會話創建)上被複制?或者我錯過了一個步驟來確保它能正常工作?
下面是一些重要的代碼片段:
Zuul代理:
@SpringBootApplication
@Controller
@EnableAutoConfiguration
@EnableZuulProxy
@EnableRedisHttpSession
public class ZuulEdgeServer {
public static void main(String[] args) {
new SpringApplicationBuilder(ZuulEdgeServer.class).web(true).run(args);
}
}
Zuul配置:
info:
component: Zuul Server
endpoints:
restart:
enabled: true
shutdown:
enabled: true
health:
sensitive: false
zuul:
routes:
service1: /**
logging:
level:
ROOT: INFO
# org.springframework.web: DEBUG
net.acesinc: DEBUG
security.sessions: ALWAYS
server:
port: 8443
ssl:
key-store: classpath:dev/localhost.jks
key-store-password: thepassword
keyStoreType: JKS
keyAlias: localhost
clientAuth: want
trust-store: classpath:dev/localhost.jks
ribbon:
IsSecure: true
後端服務:
@SpringBootApplication
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class, ThymeleafAutoConfiguration.class, org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration.class })
@EnableEurekaClient
@EnableRedisHttpSession
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
後端服務配置:
spring.jmx.default-domain: ${spring.application.name}
server:
port: 8444
ssl:
key-store: classpath:dev/localhost.jks
key-store-password: thepassword
keyStoreType: JKS
keyAlias: localhost
clientAuth: want
trust-store: classpath:dev/localhost.jks
#Change the base url of all REST endpoints to be under /rest
spring.data.rest.base-uri: /rest
security.sessions: NEVER
logging:
level:
ROOT: INFO
# org.springframework.web: INFO
# org.springframework.security: DEBUG
net.acesinc: DEBUG
eureka:
instance:
nonSecurePortEnabled: false
securePortEnabled: true
securePort: ${server.port}
homePageUrl: https://${eureka.instance.hostname}:${server.port}/
secureVirtualHostName: ${spring.application.name}
一個後端控制器:
@Controller
public class SecureContent1Controller {
private static final Logger log = LoggerFactory.getLogger(SecureContent1Controller.class);
@RequestMapping(value = {"/secure1"}, method = RequestMethod.GET)
@PreAuthorize("isAuthenticated()")
public @ResponseBody String getHomepage(ModelMap model, Principal p) {
log.debug("Secure Content for user [ " + p.getName() + " ]");
model.addAttribute("pageName", "secure1");
return "You are: [ " + p.getName() + " ] and here is your secure content: secure1";
}
}
嗨安德魯,你的問題的解決方案是在另一個問題描述http://stackoverflow.com/questions/34751700/spring-zuul-api-gateway-with-spring-session-redis-authenticate-and-route-in -sa?rq = 1#answer-38867506 – shobull
太棒了!它似乎在工作!我已經有一半的解決方案,並認爲我已經嘗試了第二部分,但我想現在不會導致它的工作!再次感謝您指出這一點! –