2020 年 6 月 3 日

IT Skills 波林

Polin WEI – 資訊工作者的技術手札

Spring Boot 身份認證 (Authentication) 使用資料庫 (Database)

1 min read
水火同源

Spring Boot 身份認證 (authentication)使用資料庫

Spring Boot 客製化 登入 ( Login ) 與 認證 (Authenticate) 機制中我們使用固定的帳號來作身份認證 (authentication),但在實務上這並不實用,因為不可能增加或減少帳號,就來修改程式,最好的方法就是將帳號維護於資料庫 (Database) 內,這樣就可以方便管理者作日常維護了。

首先要修改 table: user 的欄位

DROP TABLE IF EXISTS `user`;
CREATE TABLE user (
 id bigint NOT NULL AUTO_INCREMENT,
 username VARCHAR(50) NOT NULL,
 password VARCHAR(100) NOT NULL,
 avatar VARCHAR(100),
 first_name VARCHAR(50) NOT NULL,
 last_name VARCHAR(50) NOT NULL,
 email VARCHAR(50) NOT NULL,
 login_error_times int,
 enabled boolean,   
 account_non_locked boolean,    
 last_password_reset_date timestamp NOT NULL,
 active_date datetime,
 inactive_date datetime,
 create_date datetime DEFAULT CURRENT_TIMESTAMP,
 update_date datetime,
 create_user bigint,
 update_user bigint,
 CONSTRAINT user_pkey PRIMARY KEY (id),
 CONSTRAINT uk_username UNIQUE KEY(username)
);

再來對 Entity: user.java 作修改

這裡要實作 org.springframework.security.core.userdetails.UserDetails ,其中主要的重點是透過  public Collection<? extends GrantedAuthority> getAuthorities() 提供 Authorities,在 JPA (Java Persistence API) Many-To-Many Relationship 在 Model 上的設置 已經取得帳號所有的 Authority,再利用 mapToGrantedAuthorities(Set<Authority> authorities) 轉換成 Spring Security 需要的 Authorities 格式即可。

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {      
 return mapToGrantedAuthorities(getRoles());
}

private static List<GrantedAuthority> mapToGrantedAuthorities(Set<Authority> authorities) {     
 return authorities.stream()
   .map(Authority -> new SimpleGrantedAuthority("ROLE_" + Authority.getName()))
   .collect(Collectors.toList());
}

至於 isAccountNonExpired(), isCredentialsNonExpired(), isEnabled() 則可以使用 active_date & inactive_date 來作判斷即可。

public Boolean getEnabled() {
 Boolean isEnable = false;
 Date today = new Date(); // this object contains the current date value
 if ( active_date.before(today) ) {
  isEnable = true;
  if( Objects.nonNull(inactive_date) ) {
   if (inactive_date.before(today)) {
    isEnable = false;
   }
  }
 }
 return isEnable;
}
@Override
public boolean isAccountNonExpired() {      
 return getEnabled();
}
@Override
public boolean isCredentialsNonExpired() {      
 return getEnabled();
}
@Override
public boolean isEnabled() {        
 return getEnabled();
}

 

整個程式碼 Entity: User.java 如下

@Entity
public class User implements UserDetails {

 @Id
 @GeneratedValue(strategy = IDENTITY)
 private Long id;
 
 private String username;
 private String password;
 private String avatar;
 private String first_name;
 private String last_name;
 private String email;
 private Boolean enabled;
 private Boolean account_non_locked;
 private int login_error_times;
 private Timestamp last_password_reset_date;
 private Timestamp active_date;
 private Timestamp inactive_date;
 private Timestamp create_date;
 private Timestamp update_date;
 private Long create_user;
 private Long update_user;
 
 @ManyToMany(fetch = FetchType.EAGER)
 @JoinTable(name = "user_authority",
  joinColumns = @JoinColumn(name = "user_id"),
  inverseJoinColumns = @JoinColumn(name = "authority_id") )
 private Set<Authority> roles;    

 public Boolean getEnabled() {
  Boolean isEnable = false;
  Date today = new Date(); // this object contains the current date value
  if ( active_date.before(today) ) {
   isEnable = true;
   if( Objects.nonNull(inactive_date) ) {
    if (inactive_date.before(today)) {
     isEnable = false;
    }
   }
  }
  return isEnable;
 }
 private static List<GrantedAuthority> mapToGrantedAuthorities(Set<Authority> authorities) {    
  return authorities.stream()
    .map(Authority -> new SimpleGrantedAuthority("ROLE_" + Authority.getName()))
    .collect(Collectors.toList());
 }
 @Override
 public Collection<? extends GrantedAuthority> getAuthorities() {     
  return mapToGrantedAuthorities(getRoles());
 }
 @Override
 public boolean isAccountNonExpired() {     
  return getEnabled();
 }
 @Override
 public boolean isAccountNonLocked() {      
  return getAccount_non_locked();
 }
 @Override
 public boolean isCredentialsNonExpired() {     
  return getEnabled();
 }
 @Override
 public boolean isEnabled() {       
  return getEnabled();
 }
 
 // 後面記得要寫標準的 constructors, getters, and setters
}

 

最後再修改 UserDetailsService 的實作 AppUserDetailsService.java, 將固定的帳號置換如下,就完成了。

@Service
public class AppUserDetailsService implements UserDetailsService {
 private final Logger logger = LoggerFactory.getLogger(this.getClass());

 @Autowired
 UserRepository userRepo;

 @Override
 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  // 取得 MariaDB 裡的帳號
  com.apps.db.maria.model.User dbUser = userRepo.findByUsername(username);
  
  if (!Objects.isNull(dbUser)) {
   return dbUser;
  } else {
   throw new UsernameNotFoundException("User not found by name: " + username);
  }
  return toUserDetails(user.get());
 }
    
}

 

Copyright © All rights reserved. | Newsphere by AF themes.