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