Spring Security WebFlux從資料庫取得使用者驗證的配置。
範例環境:
- Windows 64 Bit
- Java 11
- Eclipse Version: 2019-03 (4.11.0)
- Spring Boot版本2.1.6.RELEASE
- Spring Data MongoDB
- MongoDB
- Maven
在Spring Web MVC的Spring Security從資料庫取得驗證用的使用者資訊時,通常會實作UserDetailsService
介面並將其註冊為bean
,但由於Spring WebFlux是Reactive Programming,在Spring 5後Spring Security才有支援,並且要改為實作ReactiveUserDetailsService
並註冊為bean。
下面是Spring Data MongoDB的實體類別Member
。
Member
package com.abc.demo.entity;
import java.util.Collection;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.CollectionUtils;
@Document(collection = "members")
public class Member {
@Id
private String id;
@Field("name")
private String name;
@Field("password")
private String password;
@Field("email")
private String email;
@Field("roles")
private Collection<String> roles;
/** 轉自訂的member為Spring Security的UserDetails */
public UserDetails toUserDetails() {
return User.withUsername(name)
.password(password)
.roles(roles.toArray(String[]::new)) // Java 11 Collection to array
.build();
}
}
DemoUserDetailsService
實作Spring Security WebFlux的ReactiveUserDetailsService
並覆寫findByUsername(String username)
方法來取得使用者資料,在此便可透過DAO層,也就是下面的MemberRepo
去資料庫(本範例為MongoDB)根據傳入的使用者名稱來查詢使用者資料(UserDetails
)並回傳Spring Security WebFlux進行後續的登入驗證。
DemoUserDetailsService
package com.abc.demo.config.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import com.abc.demo.entity.Member;
import com.abc.demo.repo.MemberRepo;
@Service // 讓Spring @componetScan 註冊為Bean
public class DemoUserDetailsService implements ReactiveUserDetailsService {
@Autowired
private MemberRepo memberRepo; // DAO layer to access database
@Override
public Mono<UserDetails> findByUsername(String username) {
var example = Example.of(Member.builder().name(username).build()); // Query by Example
return memberRepo.findOne(example)
.map(e -> Mono.just(e.toUserDetails())) // wrap by Mono
.orElse(Mono.error(new UsernameNotFoundException("User Not Found")));
}
}
參考:
沒有留言:
張貼留言