WebFlux 和 Spring Security 會碰出哪些火花?

airland發表於2021-09-09

WebFlux 系列松哥已經連著寫了十幾篇了,Spring Security 系列之前更是發了 68 篇(公號後臺回覆 ss 獲取系列教程),不過之前這兩個教程都是分開講的,還沒有把這兩個融合到一起講過。

隨著 WebFlux 的發展,我們有必要來了解下在響應式程式設計中如何使用 Spring Security。今天松哥就透過一個簡單的案例來和大家分享下如何在 WebFlux 中使用 Spring Security。

1.基於記憶體的使用

先來看一個簡單的,就是把使用者資訊儲存在記憶體中。

首先我們來建立一個新的專案,引入 WebFlux 和 Spring Security 依賴,如下:

圖片描述

專案建立成功後,我們新增一個介面,用來獲取登入使用者資訊,如下:

@RestController
public class UserController {
    @GetMapping("/user")
    public MonoPrincipal> getCurrentUser(MonoPrincipal> principal) {
        return principal;
    }
}

注意我們的返回值是 Mono,介面的引數也是支援 Mono 的。

這就可以了,接下來我們啟動專案,在啟動的過程中,控制檯就會列印出預設的使用者密碼,拿著預設的使用者密碼以及預設使用者名稱 user 去登入,登入完成後就可以訪問 /user 介面了,這個過程和普通的 Spring Security 用法並沒有什麼差異,所以我就不多說了,如果大家對普通的 Spring Security 用法還不熟悉,也可以看看松哥的新書《深入淺出 Spring Security》。

如果我們想配置基於記憶體的使用者資訊,該怎麼配置呢?新增如下配置類即可:

@Configuration
public class SecurityConfig {
    @Bean
    MapReactiveUserDetailsService mapReactiveUserDetailsService() {
        UserDetails ud1 = User.withUsername("admin")
                .password("{noop}123")
                .roles("admin")
                .build();
        UserDetails ud2 = User.withUsername("zhangsan")
                .password("{noop}123")
                .roles("user")
                .build();
        return new MapReactiveUserDetailsService(ud1, ud2);
    }
}

只需要提供一個 MapReactiveUserDetailsService 例項即可。

MapReactiveUserDetailsService 實現了 ReactiveUserDetailsService 介面,ReactiveUserDetailsService 介面其實就跟我們以前的 UserDetailsService 介面的作用差不多;而 MapReactiveUserDetailsService 則類似於我們以前的 InMemoryUserDetailsManager,都是基於記憶體來管理使用者的,理解了這一層,剩下的東西就好懂了。

我們在 MapReactiveUserDetailsService 中提供兩個使用者物件即可。

最後啟動專案,此時 IDEA 控制檯就不會輸出預設生成的密碼了,這個時候我們就可以直接使用 admin/123 或者 user/123 來進行登入了。

2.基於資料庫的使用

第一小節我們是在記憶體中配置使用者,真正到了開發中我們還是需要從資料庫中讀取使用者資料,所以接下來我們再來看一個基於資料庫的配置。

首先我們先來大概看一眼資料庫:

圖片描述

首先我們建立專案,這個時候要新增的依賴就比較多,除了 WebFlux 和 Spring Security 之外,還有 R2DBC 以及 MySQL 驅動,如下:

圖片描述

專案建立成功之後,在 application.properties 中配置資料庫基本資訊,如下:

spring.r2dbc.url=r2dbcs:mysql://localhost:3306/test01
spring.r2dbc.username=root
spring.r2dbc.password=123

如此之後,我們的準備工作就算完成了。

接下來我們建立 User 的實體類,老規矩,User 類需要實現 UserDetails 介面:

public class User implements UserDetails {
    @Id
    private Long id;
    private String username;
    private String address;
    private String password;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public Collection? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

接下來建立 UserRepository:

public interface UserRepository extends ReactiveCrudRepositoryUser,Long> {
    MonoUserDetails> findUserByUsername(@Param("username") String username);
}

增加了一個 findUserByUsername 方法,用來根據使用者名稱查詢使用者物件。

接下來定義 UserService,這次需要我們自己實現 ReactiveUserDetailsService 介面,如下:

@Service
public class UserService implements ReactiveUserDetailsService {

    @Autowired
    UserRepository userRepository;
    @Override
    public MonoUserDetails> findByUsername(String username) {
        return userRepository.findUserByUsername(username);
    }
}

UserService 實現了 ReactiveUserDetailsService 介面,並重寫了 findByUsername 方法,這個類似於我們之前重寫 UserDetailsService#loadUserByUsername 方法。

這裡記得將 UserService 註冊到 Spring 容器中,接下來就不需要額外的工作了。

配置完成了。

接下來我們啟動專案,此時就可以透過資料庫中的使用者進行登入了。

3.小結

好啦,今天就透過兩個簡單的小案例,帶領小夥伴們體驗下 WebFlux+Spring Security 的用法,當然這裡還有很多使用細節,在接下來的文章中松哥再和大家一一介紹。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/964/viewspace-2807078/,如需轉載,請註明出處,否則將追究法律責任。

相關文章