---
# System prepended metadata

title: 競賽程式整理-公版

---

# 競賽程式整理-公版

## 目錄

## 功能說明

- 註冊(前台)
  - 註冊(前台)功能不需權限
  - 註冊成功後在資料庫新增一組身份為 USER 的帳號

    ```flow
    start=>start: 註冊(前台)
    existCond=>condition: 帳號是否存在
    existExcep=>end: 帳號已存在錯誤
    inUser=>inputoutput: 儲存使用者
    inUserRole=>inputoutput: 儲存使用者身份
    end=>end: 註冊成功

    start->existCond
    existCond(yes)->existExcep
    existCond(no,bottom)->inUser->inUserRole->end
    ```

- 註冊(後台)
  - 註冊(後台)功能需 ADMIN 權限
  - 註冊成功後在資料庫新增一組身份為 ADMIN 的帳號

    ```flow
    start=>start: 註冊(後台)
    AuthCond=>condition: 驗證
    AuthExcep=>end: 驗證錯誤
    existCond=>condition: 帳號是否存在
    existExcep=>end: 帳號已存在錯誤
    inUser=>inputoutput: 儲存使用者
    inUserRole=>inputoutput: 儲存使用者身份
    end=>end: 註冊成功

    start->AuthCond
    AuthCond(no)->AuthExcep
    AuthCond(yes)->existCond
    existCond(yes)->existExcep
    existCond(no,bottom)->inUser->inUserRole->end
    ```

- 登入
  - 登入功能不需權限
  - 登入成功後產生一組 token，將 (userUuid,token) 存入快取，並回傳帳號和 token
    :::info
    token 的有效時間為 15 分鐘
    :::

    ```flow
    start=>start: 登入
    existCond=>condition: 驗證是否有此帳號
    existExcep=>end: 無此帳號錯誤
    pwCond=>condition: 驗證密碼是否正確
    pwExcep=>end: 密碼錯誤
    generateToken=>operation: 建立 token
    inputCache=>inputoutput: 存入快取
    end=>end: 登入成功

    start->existCond
    existCond(no)->existExcep
    existCond(yes)->pwCond
    pwCond(yes)->generateToken->inputCache->end
    pwCond(no)->pwExcep
    ```

- 登出
  - 登出功能需要 USER 以上權限
  - 登出成功後將此帳號從快取中刪除

    ```flow
    start=>start: 登出
    AuthCond=>condition: 驗證
    AuthExcep=>end: 驗證錯誤
    parseToken=>operation: 解析 token
    evictCache=>inputoutput: 清除使用者快取
    end=>end: 登出成功

    start->AuthCond
    AuthCond(no)->AuthExcep
    AuthCond(yes)->parseToken->evictCache->end
    ```

- 變更啟用狀態
  - 變更啟用狀態功能需要 ADMIN 權限
  - 變更使用者帳號的啟用狀態

    ```flow
    start=>start: 變更啟用狀態
    authCond=>condition: 驗證
    authExcep=>end: 驗證錯誤
    userIn=>inputoutput: 取得使用者
    userExistCond=>condition: 使用者是否存在
    userExistExcep=>end: 使用者不存在錯誤
    userCond=>condition: 使用者是否為 USER
    userExcep=>end: 使用者權限錯誤
    statusIn=>inputoutput: 更改啟用狀態 
    end=>end: 變更啟用狀態成功
    
    start->authCond
    authCond(no)->authExcep
    authCond(yes,bottom)->userIn->userExistCond
    userExistCond(no)->userExistExcep
    userExistCond(yes,bottom)->userCond
    userCond(no)->userExcep
    userCond(yes,bottom)->statusIn->end
    ```

- 驗證
  1. 檢核此 URI 是否需要驗證
  2. 檢核 token 格式是否有誤
  3. 檢核快取中的 token 和 Header 傳入的 token 是否相同
  4. 檢核 token 是否過期

    ```flow
    start=>start: 驗證
    excludeCond=>condition: 是否需要驗證
    authExistCond=>condition: 是否有 Auth
    AuthExcep=>end: 無 Auth 錯誤
    validateTokenCond=>condition: Token 是否錯誤
    validateTokenExcep=>end: Token 格式錯誤
    parseToken=>operation: 解析 Token
    CacheCond=>condition: Token 
    是否和快取相同
    CacheExcep=>end: Token 和登入錯誤
    TokenExpiredCond=>condition: Token 是否過期
    TokenExpiredExcep=>end: Token 過期錯誤
    setAuthentication=>operation: 設定身份
    end=>end: 驗證成功

    start->excludeCond
    excludeCond(no)->end
    excludeCond(yes)->authExistCond
    authExistCond(no)->AuthExcep
    authExistCond(yes)->validateTokenCond
    validateTokenCond(no,bottom)->parseToken->CacheCond
    validateTokenCond(yes)->validateTokenExcep
    CacheCond(no)->CacheExcep
    CacheCond(yes)->TokenExpiredCond
    TokenExpiredCond(no,bottom)->setAuthentication->end
    TokenExpiredCond(yes)->TokenExpiredExcep
    ```

## 架構

![Structure](https://i.imgur.com/I1Gka3d.png)

:::spoiler 詳細架構
![DetailStructure1](https://i.imgur.com/mCrQQI6.png)
![DetailStructure2](https://i.imgur.com/NlOgiaX.png)
![DetailStructure3](https://i.imgur.com/YEBNnJt.png)
:::

## 快取

- **Token Cache**

    | name  | type   | data     |
    |:----- |:------ |:-------- |
    | key   | String | userUuid |
    | value | String | token    |

- **Role Cache**

    | name  | type        | data     |
    |:----- |:----------- |:-------- |
    | key   | String      | userUuid |
    | value | UserDetails | 身分權限   |

## 資料庫

**MySQL**

- **sys_user 會員明細**

    | column        | type        | comment        |
    |:------------- |:----------- |:-------------- |
    | id(PK)        | BIGINT(20)  |                |
    | user_account  | VARCHAR(32) | 帳號            |
    | user_password | VARCHAR(75) | 密碼（SHA256）  |
    | user_uuid     | VARCHAR(32) | 用於驗證身份     |
    | user_enable   | VARCHAR(1) | 是否啟用        |

- **sys_role 身份**

    | column      | type        | comment  |
    | ----------- | ----------- | -------- |
    | id(PK)      | BIGINT(20)  |          |
    | role_name   | VARCHAR(32) | 身份      |

- **sys_user_roles 會員及身份關聯表**

  - 關聯會員所擁有的身份，一個會員可多個身份，可透過此表查詢該會員所擁有的身份。

    | column  | type   | comment |
    | ------- | ------ | ------- |
    | id(PK)  | BIGINT |         |
    | user_id | BIGINT |         |
    | role_id | BIGINT |         |

## API

1. **註冊(前台)**

    :::info
    **`POST`**  /api/v1/auth/sign
    :::

    - RequestBody

    ```json=
    {
       "userAccount":"user001",
       "userPassword":"root"
    }
    ```

    - ResponseBody

    ```json=
    {
        "message": "OK"
    }
    ```  

2. **註冊(後台)**

    :::info
    **`POST`**  /api/v1/auth/sign/admin
    :::

    - RequestBody

    ```json=
    {
       "userAccount":"admin",
       "userPassword":"password"
    }
    ```

    - ResponseBody

    ```json=
    {
        "message": "OK"
    }
    ```

3. **登入**

    :::info
    **`POST`**  /api/v1/auth/login
    :::
    - admin帳號預設為 admin ，密碼為 password
    - RequestBody

    ```json=
    {
       "userAccount":"user001",
       "userPassword":"root"
    }
    ```

    - ResponseBody

    ```json=
    {
        "userAcoount":"user001",
        "token":"token"
    }
    ```

4. **登出**

    :::info
    **`POST`**  /api/v1/auth/logout
    :::

    - ResponseBody

    ```json=
    {
        "message": "OK"
    }
    ```

5. **變更啟用狀態**

   :::info
   **`POST`** /api/v1/auth/enable
   :::

   - RequestBody

   ```json=
   {
       "userAccount":"user001",
       "userEnable":"N"
   }
   ```

   - ResponseBody

   ```json=
   {
      "userAccount":"user001",
      "userEnable":"N"
   }
   ```

## 環境建置

### 1. 需要的環境

[Intellij](https://hackmd.io/_TeugP3vRC-A2BXmaB6arQ)

[MariaDB](https://hackmd.io/huMkJeDCQMifhIDpEYeqww?view)

### 2. 在 Intellij 匯入專案

點選 Open

![1](https://i.imgur.com/JQ8bXTG.jpg)

到專案 backend 資料夾後，點選 ok。

![2](https://i.imgur.com/7rTfMkJ.jpg)

開啟 application.properties 修改成自己的資料庫帳號密碼。

![3](https://i.imgur.com/ohh48k1.jpg)

### 3. 開啟 HeidiSQL

點選檔案，點選載入 SQL 檔案，載入專案 backend 資料夾下的 initsql.sql 檔案

![4](https://i.imgur.com/0Qb854c.jpg)

![5](https://i.imgur.com/1WYbkX0.png)

點選執行

![6](https://i.imgur.com/WtXUrNi.jpg)

重新整理後即可看到 f62mt 資料庫

![7](https://i.imgur.com/DstbY8N.jpg)

### 4. 回到 Intellij 執行專案

開啟 F62MTemplateApplication

點選執行三角形，即可開始使用專案

![8](https://i.imgur.com/9l4USli.jpg)

## 操作流程

使用者

![9](https://i.imgur.com/55u0kVL.png)

管理者

![10](https://i.imgur.com/LoNe0c1.png)
