一、前言
由於leader要求在搭好的spring cloud 框架中加入對微服務的認證包括單點登錄認證,來確保系統的安全,所以研究了Spring Cloud Security這個組件。在前面搭好的demo中,如何確保微服務的安全,為整個系統添加安全控制,就需要用到Spring Cloud Security。用戶通過服務網關zuul來訪問任何一個微服務的時候,都需要跳轉到第三方的認證比如github或者自己搭好的CAS單點登錄服務,當認證通過才能訪問對應的服務。在研究spring cloud security 之前先對一些概念進行了解了。
OAuth2(重點),參考文檔:
http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
Spring Security OAuth2,參考文檔:http://docs.spring.io/spring-boot/docs/1.5.2.RELEASE/reference/htmlsingle/#boot-features-security-oauth2
在這個文章中主要記錄當用戶通過服務網關zuul入口訪問任何一個微服務。需要先跳轉到GitHub,使用Github進行認證,認證通過之后才能跳轉到訪問我們提供的微服務。
二、詳細實現
2.1 准備工作
(1) 前往https://github.com/settings/developers
,點擊“Register a new application”按鈕,添加一個應用。點擊按鈕后,界面如下圖所示。Homepage URL 和callback url是寫zuul的端口。
(2) 點擊“Register application”按鈕,即可出現如下圖的界面。
記住這邊的Client ID以及Client Secret,后面有用。
至此,准備工作就完成了。
2.2 編碼
代碼測試成功之后的Github地址:https://github.com/LoveIpo/spring-cloud-demo/tree/master/Zuul_CAS
這個Zuul_CAS是在zuul中進一步完善!
在這里,我們正式進行編碼。因為我是在服務網關zuul中添加單點登錄的服務認證授權。所以對前面demo中的zuul 工程進一步完善。
(1) 在pom.xml文件為應用添加spring-cloud-starter-oauth2、spring-cloud-starter-security兩個依賴。
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-security</artifactId> </dependency> </dependencies>
(2) 在zuul的啟動類中添加如下代碼
@SpringBootApplication @EnableZuulProxy @RestController public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } @GetMapping("/") public String welcome() { return "welcome"; } @RequestMapping("/user") public Principal user(Principal user) { return user; } @Component @EnableOAuth2Sso // 實現基於OAuth2的單點登錄,建議跟蹤進代碼閱讀以下該注解的注釋,很有用 public static class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http. antMatcher("/**") // 所有請求都得經過認證和授權 .authorizeRequests().anyRequest().authenticated() .and().authorizeRequests().antMatchers("/","/anon").permitAll() .and() // 這里之所以要禁用csrf,是為了方便。 // 否則,退出鏈接必須要發送一個post請求,請求還得帶csrf token // 那樣我還得寫一個界面,發送post請求 .csrf().disable() // 退出的URL是/logout .logout().logoutUrl("/logout").permitAll() // 退出成功后,跳轉到/路徑。 .logoutSuccessUrl("/login"); } } }
如代碼所示,在這里,我們使用@EnableOAuth2Sso 注解,啟用了“基於OAuth2的單點登錄”,做了一些安全配置;同時,還定義了兩個端點,/ 端點返回“welcome”字符串,/user 端點返回當前登錄用戶的認證信息。
這里說明一下,@EnableOAuth2Sso注解。如果WebSecurityConfigurerAdapter類上注釋了@EnableOAuth2Sso注解,那么將會添加身份驗證過濾器和身份驗證入口。
如果只有一個@EnableOAuth2Sso注解沒有編寫在WebSecurityConfigurerAdapter上,那么它將會為所有路徑啟用安全,並且會在基於HTTP Basic認證的安全鏈之前被添加。詳見@EnableOAuth2Sso的注釋。
(3) 修改zuul 的application.yml文件,部分代碼如下
server: port: 7073 security: user: password: user # 直接登錄時的密碼 ignored: / sessions: never # session策略 oauth2: sso: loginPath: /login # 登錄路徑 client: clientId: 你的clientId clientSecret: 你的clientSecret accessTokenUri: https://github.com/login/oauth/access_token userAuthorizationUri: https://github.com/login/oauth/authorize resource: userInfoUri: https://api.github.com/user preferTokenInfo: false spring: application: name: zuul eureka: client: serviceUrl: defaultZone: http://localhost:7071/eureka/
這樣,通過服務網關zuul來訪問任何一個服務都要跳轉到github進行認證的主要代碼就編寫完成了。
2.3 測試
(1) 啟動Eureka、zuul、serviceA
(2) 當通過服務網關zuul(端口7073) 訪問serviceA 的url:
http://localhost:7073/api-a/add?a=111&b=113
時。頁面會自動跳轉到github進行認證。你也可以通過zuul訪問serviceB也會自動跳轉到github進行認證之后才能回調到serviceB。(3) 當輸入github的用戶名和密碼認證通過之后,會出現serviceA的調用結果。如下圖所示
(4) 當你認證通過之后輸入http://localhost:7073/user
可以看到你github 的用戶信息。