天天看點

認證鑒權與API權限控制在微服務架構中的設計與實作:更新

概述

在之前的系列文章認證鑒權與API權限控制在微服務架構中的設計與實作中,我們有四篇文章講解了微服務下的認證鑒權與API權限控制的實作。當時基于的Spring Cloud版本為

Dalston.SR4

,目前最新的Spring Cloud版本為

Finchley.SR1

,對應的Spring Boot也更新到了

2.0.x

。Spring Cloud版本為

Finchley

和Spring Boot2.0相對之前的版本有較大的變化,至于具體的changes,請參見官網。本次會将項目更新到最新版本,下面具體介紹其中的變化。與使用之前的版本,請切換到

1.0-RELEASE

更新依賴

将Spring Boot的依賴更新為

2.0.4.RELEASE

1<parent>
2    <groupId>org.springframework.boot</groupId>
3    <artifactId>spring-boot-starter-parent</artifactId>
4    <version>2.0.4.RELEASE</version>
5</parent>           

複制

更新dependencyManagement中的spring-cloud依賴為

Finchley.RELEASE

1<dependencyManagement>
 2     <dependencies>
 3         <dependency>
 4             <groupId>org.springframework.cloud</groupId>
 5             <artifactId>spring-cloud-dependencies</artifactId>
 6             <version>Finchley.RELEASE</version>
 7             <type>pom</type>
 8             <scope>import</scope>
 9         </dependency>
10     </dependencies>
11</dependencyManagement>           

複制

删除

spring-cloud-starter-oauth2

依賴,隻留下

spring-cloud-starter-security

依賴。

工具更新

flyway

我們在項目中,引入了flyway的依賴,用以初始化資料庫的增量腳本,具體可以參見資料庫版本管理工具Flyway應用。

docker容器

為了更加簡便的體驗本項目,筆者在項目中提供了docker compose腳本。在本地安裝好docker compose的情況下,進入項目根目錄執行

docker-compose up

指令。

認證鑒權與API權限控制在微服務架構中的設計與實作:更新

即可啟動我們所需要的mysql和redis。

Mybatis和HikariCP

在Spring Boot 2.0.X版本中,選擇了HikariCP作為預設資料庫連接配接池。是以我們并不需要額外配置DataSource。

Mybatis的mapper和config-location配置也通過配置檔案的形式,是以

DatasourceConfig

大大簡化。

application.yml

1spring:
 2  flyway:
 3    baseline-on-migrate: true
 4    locations: classpath:db
 5  datasource:
 6    hikari:
 7      connection-test-query: SELECT 1
 8      minimum-idle: 1
 9      maximum-pool-size: 5
10      pool-name: dbcp1
11    driver-class-name: com.mysql.jdbc.Driver
12    url: jdbc:mysql://localhost:3306/auth?autoReconnect=true&useSSL=false
13    username: ${AUTH_DB_PWD:root}
14    password: ${AUTH_DB_USER:_123456_}
15#    schema[0]: classpath:/auth.sql
16#    initialization-mode: ALWAYS
17    type: com.zaxxer.hikari.HikariDataSource
18  redis:
19    database: 0
20    host: localhost
21    port: 6379
22
23mybatis:
24  mapper-locations: classpath:/mybatis/mapper/*Mapper.xml
25  config-location: classpath:/mybatis/config.xml           

複制

配置類更新

AuthenticationManagerConfig

棄用,由于循環依賴的問題,将

AuthenticationManager

的配置放置到

WebSecurityConfig

中。

WebSecurityConfig

添加了來自

AuthenticationManagerConfig

AuthenticationManager

配置。

由于Spring Security5預設

PasswordEncoder

不是

NoOpPasswordEncoder

,需要手動指定。原來的auth項目中沒有對密碼進行加密,

NoOpPasswordEncoder

已經被廢棄,隻适合在測試環境中使用,本次我們使用

SCryptPasswordEncoder

密碼加密器對密碼進行加解密,更貼近産線的使用。其他的算法還有

Pbkdf2PasswordEncoder

BCryptPasswordEncoder

關于Scrpyt算法,可以肯定的是其很難被攻擊。

Scrpyt算法是由著名的FreeBSD黑客 Colin Percival為他的備份服務 Tarsnap開發的,當初的設計是為了降低CPU負荷,盡量少的依賴cpu計算,利用CPU閑置時間進行計算,是以scrypt不僅計算所需時間長,而且占用的記憶體也多,使得并行計算多個摘要異常困難,是以利用rainbow table進行暴力攻擊更加困難。Scrpyt沒有在生産環境中大規模應用,并且缺乏仔細的審察和廣泛的函數庫支援。是以Scrpyt一直沒有推廣開,但是由于其記憶體依賴的設計特别符合當時對抗專業礦機的設計,成為數字貨币算法發展的一個主要應用方向。

而BCrypt相對出現的時間更久,也很安全。Spring Security中的

BCryptPasswordEncoder

方法采用SHA-256 + 随機鹽 + 密鑰對密碼進行加密。SHA系列是Hash算法,不是加密算法,使用加密算法意味着可以解密(這個與編碼/解碼一樣),但是采用Hash處理,其過程是不可逆的。

  1. 加密(encode):注冊使用者時,使用SHA-256+随機鹽+密鑰把使用者輸入的密碼進行hash處理,得到密碼的hash值,然後将其存入資料庫中。
  2. 密碼比對(matches):使用者登入時,密碼比對階段并沒有進行密碼解密(因為密碼經過Hash處理,是不可逆的),而是使用相同的算法把使用者輸入的密碼進行hash處理,得到密碼的hash值,然後将其與從資料庫中查詢到的密碼hash值進行比較。如果兩者相同,說明使用者輸入的密碼正确。

關于怎麼初始化密碼呢,和注冊使用者的時候怎麼給密碼加密,我們可以在初始化密碼時調用如下的方法:

1SCryptPasswordEncoder sCryptPasswordEncoder = new SCryptPasswordEncoder();
2sCryptPasswordEncoder.encode("frontend");           

複制

此時需要對資料庫中的

client_secret

進行修改,如把

frontend

修改為:

1$e0801$65x9sjjnRPuKmqaFn3mICtPYnSWrjE7OB/pKzKTAI4ryhmVoa04cus+9sJcSAFKXZaJ8lcPO1I9H22TZk6EN4A==$o+ZWccaWXSA2t7TxE5VBRvz2W8psujU3RPPvejvNs4U=           

複制

并修改配置如下:

1    @Autowired
 2    CustomAuthenticationProvider customAuthenticationProvider;
 3    @Autowired
 4    CodeAuthenticationProvider codeAuthenticationProvider;
 5
 6    @Override
 7    public void configure(AuthenticationManagerBuilder auth) throws Exception {
 8        auth.authenticationProvider(customAuthenticationProvider);
 9        auth.authenticationProvider(codeAuthenticationProvider);
10    }
11
12    @Bean
13    @Override
14    public AuthenticationManager authenticationManagerBean() throws Exception {
15        return super.authenticationManagerBean();
16    }
17
18   @Bean
19    public PasswordEncoder passwordEncoder(){
20        return new SCryptPasswordEncoder();
21    }           

複制

ResourceServerConfig

棄用,auth項目不啟用資源伺服器的功能。

OAuth2Config

由于目前版本的

spring-boot-redis

中的

RedisConnection

缺少

#set

方法,直接使用

RedisTokenStore

會出現以下異常:

1java.lang.NoSuchMethodError: org.springframework.data.redis.connection.RedisConnection.set([B[B)V           

複制

是以自定義

CustomRedisTokenStore

類,與RedisTokenStore代碼一緻,隻是将

RedisConnection#set

方法的調用替換為

RedisConnection#stringCommands#set

,如下所示:

1    conn.stringCommands().set(accessKey, serializedAccessToken);
2    conn.stringCommands().set(authKey, serializedAuth);
3    conn.stringCommands().set(authToAccessKey, serializedAccessToken);           

複制

完整代碼見文末的GitHub位址。

結果驗證

經過如上的更新改造,我們将驗證如下的API端點:

  • password模式擷取token:/oauth/token?grant_type=password
  • 重新整理token:/oauth/token?grant_type=refresh_token&refresh_token=…
  • 檢驗token:/oauth/check_token
  • 登出:/logout
  • 授權:/oauth/authorize
  • 授權碼模式擷取token:/oauth/token?grant_type=authorization_code

結果就不展示了,都可以正常使用。

小結

OAuth鑒權服務是微服務架構中的一個基礎服務,項目公開之後得到了好多同學的關注,好多同學在加入QQ群之後也提出了自己關于這方面的疑惑或者建議,一起讨論和解決疑惑的地方。随着Spring Boot和Spring Cloud的版本更新,筆者也及時更新了本項目,希望能夠幫到一些童鞋。筆者籌劃的一本關于Spring Cloud應用的書籍,本月即将出版面世,其中關于Spring Cloud Security部分,有着詳細的解析,各位同學可以支援一下正版。

本文的源碼位址

GitHub:https://github.com/keets2012/Auth-service

碼雲: https://gitee.com/keets/Auth-Service

參考

scrypt算法的前世今生(從零開始學區塊鍊 192)https://www.sohu.com/a/167016356_99901444