1. 程式人生 > 其它 >Spring 系列 (12) - Springboot+Redis(一) | 使用 Jedis 實現使用者驗證例項

Spring 系列 (12) - Springboot+Redis(一) | 使用 Jedis 實現使用者驗證例項

Redis 是一個開源(BSD許可)的,記憶體中的資料結構儲存系統,可以用作資料庫、快取和訊息中介軟體。
 
Redis 支援多種型別的資料結構,如 字串(strings)、雜湊(hashes)、 列表(lists)、集合(sets)、 有序集合(sorted sets)與範圍查詢、bitmaps、hyperloglogs 和 地理空間(geospatial)索引半徑查詢。

Redis 優勢:

    (1) 效能極高 - Redis 能讀的速度是 110000 次/s,寫的速度是 81000 次/s;
    (2) 豐富的資料型別 - Redis 支援二進位制案例的 Strings、Lists、Hashes、Sets 及 Ordered Sets 資料型別操作;
    (3) 原子 - Redis 的所有操作都是原子性的,意思就是要麼成功執行要麼失敗完全不執行。單個操作是原子性的。多個操作也支援事務,即原子性,通過 MULTI 和 EXEC 指令包起來;
    (4) 豐富的特性 - Redis 還支援 publish/subscribe、通知、key 過期等等特性。

本文使用 Redis 的 Jedis 客戶端實現使用者驗證例項。

Redis: https://github.com/redis
Jedis: https://github.com/redis/jedis


1. Redis 安裝配置

    1) Windows 下安裝

        https://github.com/tporadowski/redis/releases,本文下載 Redis-x64-5.0.14.1.msi 直接安裝(安裝後自動執行),熟悉 Windows 命令的也可以下載 *.zip 包配置執行。

        啟動一個 cmd 視窗,執行如下命令。

            C:\> redis-cli.exe -h 127.0.0.1 -p 6379

                127.0.0.1:6379> ping

                PONG

        以上命令表示 Redis 客戶端已經連線上 Redis 伺服器。

    2) Ubuntu 下安裝

        (1) apt 命令安裝

            安裝 Redis 執行如下命令

                $ sudo apt update
                $ sudo apt install redis-server

            啟動 Server

                $ redis-server

            啟動 Client

                $ redis-cli

                    redis 127.0.0.1:6379> ping

                    PONG

        (2) 原始碼安裝

            https://download.redis.io/releases/,本文下載了 redis-5.0.14.tar.gz。

            下載編譯

                $ wget https://download.redis.io/releases/redis-5.0.14.tar.gz
                $ tar -vxzf redis-5.0.14.tar.gz
                $ cd redis-5.0.14
                $ make

            啟動 Server

                $ cd src
                $ ./redis-server

            啟動 Client

                $ ./redis-cli

                    redis 127.0.0.1:6379> ping

                    PONG

    3) 設定密碼

        可以通過以下命令檢視是否設定了密碼:

            127.0.0.1:6379> CONFIG get requirepass
            1) "requirepass"
            2) ""
            
        預設情況下 requirepass 引數是空的,可以通過以下命令來設定密碼:

            127.0.0.1:6379> CONFIG set requirepass "123456"
            OK
            127.0.0.1:6379> CONFIG get requirepass
            1) "requirepass"
            2) "123456"

        設定密碼後,客戶端連線 redis 服務就需要密碼驗證。

            127.0.0.1:6379> AUTH "123456"
            OK


2. 開發環境

    Windows版本:Windows 10 Home (20H2)   
    IntelliJ IDEA (https://www.jetbrains.com/idea/download/):Community Edition for Windows 2020.1.4
    Apache Maven (https://maven.apache.org/):3.8.1
    Redis for Windows:5.0.14

    注:Spring 開發環境的搭建,可以參考 “ Spring基礎知識(1)- Spring簡介、Spring體系結構和開發環境配置 ”。


3. 建立 Spring Boot 基礎專案

    專案例項名稱:SpringbootExample12
    Spring Boot 版本:2.6.6

    建立步驟:

        (1) 建立 Maven 專案例項 SpringbootExample12;
        (2) Spring Boot Web 配置;
        
    具體操作請參考 “Spring 系列 (2) - 在 Spring Boot 專案裡使用 Thymeleaf、JQuery+Bootstrap 和國際化” 裡的專案例項 SpringbootExample02,文末包含如何使用 spring-boot-maven-plugin 外掛執行打包的內容。

    SpringbootExample12 和 SpringbootExample02 相比,SpringbootExample12 不匯入 Thymeleaf 依賴包,也不配置 jQuery、Bootstrap、模版檔案(templates/*.html)和國際化。


4. 配置 Jedis

    1) 修改 pom.xml,匯入 Jedis 依賴包

 1         <project ... >
 2             ...
 3             <dependencies>
 4                 ...
 5 
 6                 <dependency>
 7                     <groupId>redis.clients</groupId>
 8                     <artifactId>jedis</artifactId>
 9                     <version>4.0.1</version>
10                 </dependency>
11 
12                 ...
13             </dependencies>
14 
15             ...
16         </project>


        在IDE中專案列表 -> SpringbootExample12 -> 點選滑鼠右鍵 -> Maven -> Reload Project

    2) 修改 src/main/resources/application.properties 檔案,新增如下配置

        # redis
        spring.redis.database=0
        spring.redis.host=localhost
        spring.redis.port=6379
        spring.redis.password=123456
        spring.redis.timeout=5000
        spring.redis.pool.max-active=8
        spring.redis.pool.max-idle=8
        spring.redis.pool.max-wait=-1
        spring.redis.sentinel.master=
        spring.redis.sentinel.nodes=

    3) 建立 src/main/java/com/example/config/JedisConfig.java 檔案

 1         package com.example.config;
 2 
 3         import org.springframework.context.annotation.Bean;
 4         import org.springframework.beans.factory.annotation.Qualifier;
 5         import org.springframework.context.annotation.Configuration;
 6         import org.springframework.beans.factory.annotation.Value;
 7 
 8         import redis.clients.jedis.JedisPool;
 9         import redis.clients.jedis.JedisPoolConfig;
10 
11         @Configuration
12         public class JedisConfig {
13             @Value("${spring.redis.database}")
14             private Integer database;
15             @Value("${spring.redis.host}")
16             private String host;
17             @Value("${spring.redis.port}")
18             private Integer port;
19             @Value("${spring.redis.password}")
20             private String password;
21             @Value("${spring.redis.timeout}")
22             private Integer timeout;
23             @Value("${spring.redis.pool.max-active}")
24             private Integer maxActive;
25             @Value("${spring.redis.pool.max-idle}")
26             private Integer maxIdle;
27 
28             @Bean
29             public JedisPoolConfig jedisPoolConfig(){
30 
31                 JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
32                 jedisPoolConfig.setMaxTotal(maxActive);
33                 jedisPoolConfig.setMaxIdle(maxIdle);
34                 return jedisPoolConfig;
35             }
36 
37             @Bean
38             public JedisPool jedisPool(@Qualifier("jedisPoolConfig")JedisPoolConfig  jedisPoolConfig){
39 
40                 JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port,
41                                                     timeout, password, database);
42 
43                 return jedisPool;
44             }
45 
46         }


    4) 修改 src/main/java/com/example/controller/IndexController.java 檔案

 1         package com.example.controller;
 2 
 3         import org.springframework.beans.factory.annotation.Autowired;
 4         import org.springframework.stereotype.Controller;
 5         import org.springframework.web.bind.annotation.RequestMapping;
 6         import org.springframework.web.bind.annotation.ResponseBody;
 7 
 8         import redis.clients.jedis.JedisPool;
 9         import redis.clients.jedis.Jedis;
10 
11         @Controller
12         public class IndexController {
13             @Autowired
14             private JedisPool jedisPool;
15 
16             @ResponseBody
17             @RequestMapping("/test")
18             public String test() {
19 
20                 Jedis jedis = jedisPool.getResource();
21                 String str = jedis.get("redis");
22 
23                 return "Test Page: " + str;
24             }
25 
26         }


    5) 執行

        (1) 建立 Redis Key
        
            啟動一個 cmd 視窗,執行如下命令。

            C:\> redis-cli.exe -h 127.0.0.1 -p 6379

                127.0.0.1:6379> AUTH "123456"
                OK
                127.0.0.1:6379> SET redis "Redis Jedis Demo"
                OK

        (2) 測試

            訪問 http://localhost:9090/test,頁面顯示:

                Test Page: Redis Jedis Demo


5. 配置 Security

    1) 修改 pom.xml,匯入 Security 依賴包

 1         <project ... >
 2             ...
 3             <dependencies>
 4                 ...
 5 
 6                 <!-- Spring security -->
 7                 <dependency>
 8                     <groupId>org.springframework.boot</groupId>
 9                     <artifactId>spring-boot-starter-security</artifactId>
10                 </dependency>
11 
12                 ...
13             </dependencies>
14 
15             ...
16         </project>


        在IDE中專案列表 -> SpringbootExample12 -> 點選滑鼠右鍵 -> Maven -> Reload Project

     2) 修改 src/main/resources/application.properties 檔案,新增如下配置

          # security
          spring.security.user.name=admin
          spring.security.user.password=123456
          spring.security.user.roles=admin

        執行並訪問 http://localhost:9090/test,自動跳轉到 http://localhost:9090/login (Spring security 的預設頁面),輸入上面的使用者名稱和密碼登入,登入後跳轉到 http://localhost:9090/test。

    3) 建立 src/main/java/com/example/service/RedisUserDetailsService.java 檔案

 1         package com.example.service;
 2 
 3         import java.util.List;
 4         import java.util.ArrayList;
 5 
 6         import org.springframework.beans.factory.annotation.Autowired;
 7         import org.springframework.context.annotation.Configuration;
 8         import org.springframework.security.core.userdetails.User;
 9         import org.springframework.security.core.userdetails.UserDetails;
10         import org.springframework.security.core.userdetails.UserDetailsService;
11         import org.springframework.security.core.userdetails.UsernameNotFoundException;
12         import org.springframework.security.core.GrantedAuthority;
13 
14         import redis.clients.jedis.JedisPool;
15         import redis.clients.jedis.Jedis;
16 
17         @Configuration
18         public class RedisUserDetailsService implements UserDetailsService {
19             @Autowired
20             private JedisPool jedisPool;
21 
22             @Override
23             public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
24 
25                 Jedis jedis = jedisPool.getResource();
26                 String password = jedis.get(username);
27 
28                 List<GrantedAuthority> authorities = new ArrayList<>();
29 
30                 User userDetails= new User(username, password, authorities);
31                 return userDetails;
32             }
33         }


    4) 建立 src/main/java/com/example/config/WebSecurityConfig.java 檔案

 1         package com.example.config;
 2 
 3         import org.springframework.context.annotation.Bean;
 4         import org.springframework.beans.factory.annotation.Autowired;
 5         import org.springframework.context.annotation.Configuration;
 6         import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 7         import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
 8         //import org.springframework.security.core.userdetails.UserDetailsService;
 9         import com.example.service.RedisUserDetailsService;
10         import org.springframework.security.crypto.password.NoOpPasswordEncoder;
11         import org.springframework.security.crypto.password.PasswordEncoder;
12 
13         @Configuration
14         public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
15             @Autowired
16             //private UserDetailsService userDetailsService;
17             private RedisUserDetailsService redisUserDetailsService;
18 
19             @Override
20             protected void configure(AuthenticationManagerBuilder auth) throws Exception {
21                 //auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
22                 auth.userDetailsService(redisUserDetailsService).passwordEncoder(passwordEncoder());
23             }
24 
25             @Bean
26             public PasswordEncoder passwordEncoder(){
27                 return NoOpPasswordEncoder.getInstance();
28             }
29         }


    5) 執行

        (1) 建立 Redis Key
        
            啟動一個 cmd 視窗,執行如下命令。

            C:\> redis-cli.exe -h 127.0.0.1 -p 6379

                127.0.0.1:6379> AUTH "123456"
                OK
                127.0.0.1:6379> SET user "user"
                OK

        (2) 測試

            執行並訪問 http://localhost:9090/test,自動跳轉到 http://localhost:9090/login (Spring security 的預設頁面),輸入使用者/密碼: user/user,登入後跳轉到 http://localhost:9090/test。

            注:此時 application.properties 裡設定的使用者/密碼(admin/123456)無法登入。