認證鑑權與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-RELEASEjava

升級依賴

將Spring Boot的依賴升級爲2.0.4.RELEASEmysql

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.4.RELEASE</version>
</parent>
複製代碼

升級dependencyManagement中的spring-cloud依賴爲Finchley.RELEASEgit

<dependencyManagement>
     <dependencies>
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-dependencies</artifactId>
             <version>Finchley.RELEASE</version>
             <type>pom</type>
             <scope>import</scope>
         </dependency>
     </dependencies>
</dependencyManagement>
複製代碼

刪除spring-cloud-starter-oauth2依賴,只留下spring-cloud-starter-security依賴。github

工具升級

flyway

咱們在項目中,引入了flyway的依賴,用以初始化數據庫的增量腳本,具體能夠參見數據庫版本管理工具Flyway應用redis

docker容器

爲了更加簡便的體驗本項目,筆者在項目中提供了docker compose腳本。在本地安裝好docker compose的狀況下,進入項目根目錄執行docker-compose up命令。算法

便可啓動咱們所須要的mysql和redis。spring

Mybatis和HikariCP

在Spring Boot 2.0.X版本中,選擇了HikariCP做爲默認數據庫鏈接池。因此咱們並不須要額外配置DataSource。sql

Mybatis的mapper和config-location配置也經過配置文件的形式,所以DatasourceConfig大大簡化。docker

application.yml

spring:
 flyway:
 baseline-on-migrate: true
 locations: classpath:db
 datasource:
 hikari:
 connection-test-query: SELECT 1
 minimum-idle: 1
 maximum-pool-size: 5
 pool-name: dbcp1
 driver-class-name: com.mysql.jdbc.Driver
 url: jdbc:mysql://localhost:3306/auth?autoReconnect=true&useSSL=false
 username: ${AUTH_DB_PWD:root}
 password: ${AUTH_DB_USER:_123456_}
# schema[0]: classpath:/auth.sql
# initialization-mode: ALWAYS
 type: com.zaxxer.hikari.HikariDataSource
 redis:
 database: 0
 host: localhost
 port: 6379

mybatis:
 mapper-locations: classpath:/mybatis/mapper/*Mapper.xml
 config-location: classpath:/mybatis/config.xml
複製代碼

配置類升級

AuthenticationManagerConfig

棄用,因爲循環依賴的問題,將AuthenticationManager的配置放置到WebSecurityConfig中。數據庫

WebSecurityConfig

添加了來自AuthenticationManagerConfigAuthenticationManager配置。

因爲Spring Security5默認PasswordEncoder不是NoOpPasswordEncoder,須要手動指定。原來的auth項目中沒有對密碼進行加密,NoOpPasswordEncoder已經被廢棄,只適合在測試環境中使用,本次咱們使用SCryptPasswordEncoder密碼加密器對密碼進行加解密,更貼近產線的使用。其餘的算法還有Pbkdf2PasswordEncoderBCryptPasswordEncoder

關於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值進行比較。若是二者相同,說明用戶輸入的密碼正確。

關於怎麼初始化密碼呢,和註冊用戶的時候怎麼給密碼加密,咱們能夠在初始化密碼時調用以下的方法:

SCryptPasswordEncoder sCryptPasswordEncoder = new SCryptPasswordEncoder();
sCryptPasswordEncoder.encode("frontend");
複製代碼

此時須要對數據庫中的client_secret進行修改,如把frontend修改成:

$e0801$65x9sjjnRPuKmqaFn3mICtPYnSWrjE7OB/pKzKTAI4ryhmVoa04cus+9sJcSAFKXZaJ8lcPO1I9H22TZk6EN4A==$o+ZWccaWXSA2t7TxE5VBRvz2W8psujU3RPPvejvNs4U=
複製代碼

並修改配置以下:

@Autowired
    CustomAuthenticationProvider customAuthenticationProvider;
    @Autowired
    CodeAuthenticationProvider codeAuthenticationProvider;

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customAuthenticationProvider);
        auth.authenticationProvider(codeAuthenticationProvider);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

   @Bean
    public PasswordEncoder passwordEncoder(){
        return new SCryptPasswordEncoder();
    }
複製代碼

ResourceServerConfig

棄用,auth項目不啓用資源服務器的功能。

OAuth2Config

因爲當前版本的spring-boot-redis中的RedisConnection缺乏#set方法,直接使用RedisTokenStore會出現如下異常:

java.lang.NoSuchMethodError: org.springframework.data.redis.connection.RedisConnection.set([B[B)V
複製代碼

所以自定義CustomRedisTokenStore類,與RedisTokenStore代碼一致,只是將RedisConnection#set方法的調用替換爲RedisConnection#stringCommands#set,以下所示:

conn.stringCommands().set(accessKey, serializedAccessToken);
    conn.stringCommands().set(authKey, serializedAuth);
    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:github.com/keets2012/A…
碼雲: gitee.com/keets/Auth-…

訂閱最新文章,歡迎關注個人公衆號

微信公衆號

相關閱讀

認證鑑權與API權限控制在微服務架構中的設計與實現

參考

scrypt算法的前世此生(從零開始學區塊鏈 192)

相關文章
相關標籤/搜索