本篇文章開始會進入實作 JWT 驗證到後端系統裡面,本篇會先介紹本次後端系統的架構,接著會將專案拆分為好幾段,一段一段介紹裡面的概念和寫法。
首先看到這張圖,本次後端系統中的核心為 user、config、auth
user 存放的是我們的資料表相關的資訊,包括 : 「控制 user 資料表的 API、user 角色定義...」
config 會存放一些跟系統相關的設定,其中就包含了 : 「JWT 生成、JWT審核...」
auth 會執行一些跟註冊帳號有關的功能
其他剩下的還有 demo 跟 exceptionHandler,demo 是用來測試我們 JWT 驗證是否成功的測試 API,exceptionHandler 是一個全域的例外處理類,我們可以透過攔截錯誤的方式避免後端系統因為報錯而導致程式碼崩潰
本篇文章會從前面熟悉的地方開始教學,後續才會進到新的部分
這些就是我們 user 會建立的細項
這裡比較特別的只有 Role,在這裡我們會建立用戶的角色
一樣右鍵新增java class,選取 Enum
我們可以像這樣簡單的定義角色,也可以在針對角色做細項的設定,例如針對admin的讀、存、寫等等的權限做細部設定,這次專案就簡單建立角色就好
public enum Role {
//用來定義使用者的角色,例如:一般使用者、管理者...
admin,
user
}
本次的 User 資料表會使用到 UserDetails
UserDetails 為我們提供了各項帳戶的基礎設定,包括 : 「帳戶是否鎖定、帳戶憑證是否過期、帳戶是否啟用、帳戶是否過期、角色綁定...」
@Data // 建立 Getter 和 Setter
@Entity
@Table(name = "_user")
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User implements UserDetails {
當我們擴寫這個 UserDetails 時,可以對他 alt + shift 自動引入需要的方法
引入這些功能後大概就會長這個樣子
@Data // 建立 Getter 和 Setter
@Entity
@Table(name = "_user")
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User implements UserDetails {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of();
}
@Override
public String getUsername() {
return "";
}
@Override
public boolean isAccountNonExpired() {
return false;
}
@Override
public boolean isAccountNonLocked() {
return false;
}
@Override
public boolean isCredentialsNonExpired() {
return false;
}
@Override
public boolean isEnabled() {
return false;
}
}
接著就填入這次後端的欄位
@Id
@GeneratedValue
private int id;
private String firstname;
private String lastname;
private String email;
private String password;
private String describe;
@Enumerated(EnumType.STRING)//用來辨別這個role是屬於enum類別
private Role role;
接著我們要來修改一下剛剛引入的那些功能
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
//回傳使用者的角色
return List.of(new SimpleGrantedAuthority(role.name()));
}
@Override
public String getUsername() {
/* 獲取用戶名稱
* 這個實作中設定為email*/
return email;
}
@Override
public String getPassword() {
/* 獲取用戶密碼*/
return password;
}
@Override
public boolean isAccountNonExpired() {
/* 設定帳號是否過期
* false為過期,true為不過期 */
return true;
}
@Override
public boolean isAccountNonLocked() {
/* 設定帳戶是否鎖定
* false為鎖定,true為解鎖 */
return true;
}
@Override
public boolean isCredentialsNonExpired() {
/* 設定帳戶的憑證是否過期
* false為過期,true為不過期*/
return true;
}
@Override
public boolean isEnabled() {
/* 設定帳戶是否啟用
* false為停用,true為啟用 */
return true;
}
接下來 Controller、Service、Repository 都跟之前沒什麼變化,這邊就附上程式碼不多做解釋
這個專案使用輸入參數的方是將資料傳入,因為還會測試身分驗證的效果是否成功,因此這邊推薦建立各種不同的 RESTful API,在設定什麼身分能做什麼事的時候,就看的出來效果了 !
@RestController
@RequestMapping("api/v1/user")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@GetMapping("/get")
public Optional<User> getUserByEmail(
@RequestParam("email") String email
){
return userService.getUserByEmail(email);
}
@PostMapping("/post")
public List<User> postUserDescribeByEmail(
@RequestParam("describe") String describe,
@RequestParam("email") String email
){
return userService.postUserDescribeByEmail(describe, email);
}
@PutMapping("/put")
public List<User> updateUserNamesByEmail(
@RequestParam("firstname") String firstname,
@RequestParam("lastname") String lastname,
@RequestParam("email") String email
){
return userService.updateUserNamesByEmail(firstname, lastname, email);
}
@DeleteMapping("/delete")
public List<User> deleteUserByEmail(
@RequestParam("email") String email
){
return userService.deleteUserByEmail(email);
}
}
@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
Optional<User> findByEmail(String email);
@Query("select u from User u where u.id = :id")
void findById();
@Transactional
@Modifying
@Query("update User u set u.firstname = :firstname, u.lastname =:lastname where u.email = :email")
void updateUserNamesByEmail(@Param("firstname") String firstname,
@Param("lastname") String lastname,
@Param("email") String email);
@Transactional
@Modifying
@Query("delete User u where u.email = :email")
void deleteUserByEmail(@Param("email") String email);
}
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
public Optional<User> getUserByEmail(String email) {
return userRepository.findByEmail(email);
}
public List<User> postUserDescribeByEmail(String describe, String email){
User user = userRepository.findByEmail(email).orElseThrow();
user.setDescribe(describe);
userRepository.save(user);
return userRepository.findAll();
}
public List<User> updateUserNamesByEmail(String firstname, String lastname, String email){
userRepository.updateUserNamesByEmail(firstname, lastname, email);
return userRepository.findAll();
}
public List<User> deleteUserByEmail(String email) {
userRepository.deleteUserByEmail(email);
return userRepository.findAll();
}
}
本篇文章快速將前面介紹過的部分帶過,下篇文章會先將 auth 的部分完成,這個部分就會碰到一些跟 JWT 相關的設定,不過這部分會先跳過,先展示一個框架,後續的文章會再補上 JWT 的實現。