# 競賽程式整理-公版
## 目錄
## 功能說明
- 註冊(前台)
- 註冊(前台)功能不需權限
- 註冊成功後在資料庫新增一組身份為 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
```
## 架構

:::spoiler 詳細架構



:::
## 快取
- **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

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

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

### 3. 開啟 HeidiSQL
點選檔案,點選載入 SQL 檔案,載入專案 backend 資料夾下的 initsql.sql 檔案


點選執行

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

### 4. 回到 Intellij 執行專案
開啟 F62MTemplateApplication
點選執行三角形,即可開始使用專案

## 操作流程
使用者

管理者
