基于org.springframework.security.core.userdetails.User
,enabled
,accountNotExpired
和credentialsNotExpired
定制处理认证的accountNotLocked
的方式是什么?我的应用程序用户(DB)具有以下可能的状态:
PENDING
,ACTIVE
,DEACTIVATED
,BLOCKED
,SPAM
,DELETED
我写了一个自定义UserDetailsService
@Service
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UserDao userDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userDao.findByEmail(username)
.orElseThrow(() -> new UsernameNotFoundException("No account found for " + username));
return new org.springframework.security.core.userdetails.User(user.getEmail(),
user.getPassword(),true , true, true, true, getAuthorities("ROLE_USER"));
}
private Collection<? extends GrantedAuthority> getAuthorities(String role) {
return Arrays.asList(new SimpleGrantedAuthority(role));
}
}
到目前为止,我被迫将true
硬编码为Spring的User
默认具有的所有属性。我希望自己实现这些属性。
编辑:我的自定义Accont状态:
对于spam
,delete
我希望用户决定(在登录点)是否要恢复其帐户。对于spam
和blocked
,用户将能够访问主页,但除了一条消息外,其他任何内容均不可见。对于deactivated
,我想通过单击收到的电子邮件中指定的链接向用户显示他们需要激活帐户。
如何实现呢?在什么级别?
答案 0 :(得分:0)
只需扩展org.springframework.security.core.userdetails.User
类即可添加新的字段和方法(或在需要时覆盖现有字段),这可能比创建实现UserDetails
接口的新型用户对象更简单。 / p>
答案 1 :(得分:0)
首先:从
User
扩展您的UserDetails
类,并添加必要的字段,例如用户名,密码等。第二步:向其添加
enabled
,accountNotExpired
,credentialsNotExpired
和accountNotLocked
字段,并进行 最后三个为transient
,因为您不想保留它们,您 只需使用它们来检查这些条件是否符合方法。
public enum UserStatus{
PENDING,
ACTIVE,
DEACTIVATED,
BLOCKED,
SPAM,
DELETED
}
public class User implements UserDetails {
// ... Other field definitions
protected LocalDateTime expireDate;
protected UserStatus status = UserStatus.ACTIVE; // load from DB
@Transient
protected boolean accountNotExpired = true;
@Transient
protected boolean accountNotLocked = false;
@Transient
protected boolean credentialsNotExpired = true;
// ... getters & setters
}
通过实现以下方面的自定义方法来实现
userService
UserService
,更重要的是从UserDetailsService
到 实现accountNotExpired
的标准逻辑,credentialsNotExpired
和accountNotLocked
。例如,这里我仅实现
accountNotExpired
,您可以添加 您的credentialsNotExpired
和accountNotLocked
。
public class UserServiceImpl implements UserService, UserDetailsService {
private final UserRepository userRepository;
@Autowired
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) {
User user = userDao.findByEmail(username)
.orElseThrow(() -> new UsernameNotFoundException("No account found for " + username));
// check whether you account expired or not
if ((user.getExpireDate() != null) && (LocalDateTime.now().isAfter(user.getExpireDate()))) {
user.setAccountNotExpired(false);
}
// Also decide for credentialsNotExpired and accountNotLocked here
for (Role role: user.getRoles()) {
for (Permission permission: role.getPermissions()) {
user.getAuthorities().add(new SimpleGrantedAuthority(permission.getName()));
}
}
return user;
}
}
现在,根据上一步执行的条件,您将 现在处于通过实施来控制您的用户的位置
AuthenticationProvider
为:
public class CustomAuthenticationProvider implements AuthenticationProvider {
private final UserDetailsService userDetailsService;
@Autowired
public CustomAuthenticationProvider(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Override
public Authentication authenticate(Authentication authentication) {
String username = authentication.getName();
BCryptPasswordEncoder bcrypt = new BCryptPasswordEncoder();
String password = (String) authentication.getCredentials();
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (userDetails == null) {
throw new BadCredentialsException("username not found");
}
if (!bcrypt.matches(password, userDetails.getPassword())) {
throw new BadCredentialsException("password incorrect");
}
if (!userDetails.isAccountNonExpired()) {
throw new CredentialsExpiredException("account expired");
}
if (!userDetails.isCredentialsNonExpired()) {
throw new CredentialsExpiredException("password expired");
}
if (!userDetails.isAccountNonLocked()) {
throw new LockedException("account locked");
}
// decision point based on user status
if (userDetails.getUserStatus() != UserStatus.DEACTIVATED) {
throw new DisabledException("account deactivated");
}else if(userDetails.getUserStatus() != UserStatus.PENDING){
...
}else if(userDetails.getUserStatus() != UserStatus.BLOCKED){
...
}else if(userDetails.getUserStatus() != UserStatus.SPAM){
...
}else if(userDetails.getUserStatus() != UserStatus.DELETED){
...
}
return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
}
@Override
public boolean supports(Class << ? > authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}