天天看點

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

松哥原創的 Spring Boot 視訊教程已經殺青,感興趣的小夥伴戳這裡-->Spring Boot+Vue+微人事視訊教程

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

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

1.基于記憶體的使用

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

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

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

項目建立成功後,我們添加一個接口,用來擷取登入使用者資訊,如下:

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

複制

注意我們的傳回值是

Mono<Principal>

,接口的參數也是支援

Mono<Principal>

的。

這就可以了,接下來我們啟動項目,在啟動的過程中,控制台就會列印出預設的使用者密碼,拿着預設的使用者密碼以及預設使用者名 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 會碰出哪些火花?

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

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

項目建立成功之後,在 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 ReactiveCrudRepository<User,Long> {
    Mono<UserDetails> findUserByUsername(@Param("username") String username);
}
           

複制

增加了一個 findUserByUsername 方法,用來根據使用者名查找使用者對象。

接下來定義 UserService,這次需要我們自己實作 ReactiveUserDetailsService 接口,如下:

@Service
public class UserService implements ReactiveUserDetailsService {

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

複制

UserService 實作了 ReactiveUserDetailsService 接口,并重寫了 findByUsername 方法,這個類似于我們之前重寫 UserDetailsService#loadUserByUsername 方法。

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

配置完成了。

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

3.小結

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