Spring WebFlux安全配置教程和原始碼 - vinsguru

發表於2020-12-18

教程演示Spring WebFlux Security反應式Web應用程式的安全性。

假設一個具有3個API端點的簡單應用程式。我們需要具有如下所示的安全性。 

路徑:/home/admin   角色:ADMIN
路徑:/home/user    角色:ADMIN, USER
路徑:/home/any     角色:ADMIN

 

第一步:

我使用以下端點建立一個REST控制器:

@RestController
@RequestMapping("home")
public class AuthController {

    @GetMapping("user")
    public Mono<String> userHome(){
        return Mono.just("user home");
    }

    @GetMapping("admin")
    public Mono<String> adminHome(){
        return Mono.just("admin home");
    }

    @GetMapping("any")
    public Mono<String> any(){
        return Mono.just("authenticated home");
    }

}

Spring WebFlux安全配置:

  • 建立一個配置類,以使用允許的角色/許可權配置路徑,如下所示。
  • 只要經過身份驗證,應用程式中的任何人都可以使用任何其他路徑(例如:/ home / any)。

@EnableWebFluxSecurity
public class WebSecurityConfig {

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http.authorizeExchange()
                .pathMatchers("/home/user").hasAnyRole("USER", "ADMIN")
                .pathMatchers("/home/admin").hasRole("ADMIN")
                .anyExchange()
                .authenticated()
                .and()
                .formLogin();
        return http.build();
    }

}

@EnableReactiveMethodSecurity

如果您不喜歡上面的配置路徑匹配器和角色方法,我們可以使安全性保持簡單,如下所示。

@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class WebSecurityConfig {

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http.authorizeExchange()
                .anyExchange()
                .authenticated()
                .and()
                .formLogin();
        return http.build();
    }

}

我們可以在方法上新增PreAuthorize / PostAuthorize註釋以提供類似的行為。

@GetMapping("user")
@PreAuthorize("hasRole('USER')")
public Mono<String> userHome(){
    return Mono.just("user home");
}

@GetMapping("admin")
@PreAuthorize("hasRole('ADMIN')")
public Mono<String> adminHome(){
    return Mono.just("admin home");
}

 

第二步 使用者資料庫:

我需要一個使用者資料庫。我正在將Map用於此演示目的。

  • 我們需要使用使用者名稱,密碼和使用者特定角色來構建UserDetails物件

@Configuration
public class UserDB {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Bean
    public Map<String, UserDetails> map(){
        return Map.of(
                "user", User.withUsername("user").password(passwordEncoder.encode("user")).roles("USER").build(),
                "admin", User.withUsername("admin").password(passwordEncoder.encode("admin")).roles("ADMIN").build(),
                "any", User.withUsername("any").password(passwordEncoder.encode("any")).authorities(Collections.emptyList()).build()
        );
    }

}

 

最後一步,我們需要ReactiveUserDetailsS​​ervice實現根據使用者名稱返回使用者詳細資訊。

@Service
public class UserDetailsServiceImpl implements ReactiveUserDetailsService {

    @Autowired
    private Map<String, UserDetails> map;

    @Override
    public Mono<UserDetails> findByUsername(String username) {
       return Mono.just(this.map.get(username));
    }

}

  

啟動應用程式。嘗試訪問任何上述配置的端點。該應用程式將自動將您重定向到登入頁面。

 

相關文章