# 建立 Amplify Next 專案 + 設定 Gen2 Backend 功能 ###### 參考資料: * https://docs.amplify.aws/nextjs/start/quickstart/nextjs-app-router-client-components/ * https://docs.amplify.aws/react/build-a-backend/data/set-up-data/ * https://docs.amplify.aws/react/build-a-backend/auth/use-existing-cognito-resources/ --- AWS 提供的 Amplify 有資料庫功能結合前端框架,很適合個人網站或客製化的中小型網站使用,實現全端架構的網站! --- ### 建立專案 ###### Note:建立新的 Amplify App 需要 AWS管理員 開放 [IAM 角色權限](https://docs.aws.amazon.com/zh_tw/amplify/latest/userguide/security-iam-awsmanpol.html) 1. 先[從模板建立專案](https://github.com/new?template_name=amplify-next-template&template_owner=aws-samples&name=amplify-next-template&description=My%20Amplify%20Gen%202%20starter%20application)後,在 [Amplify控制台](https://console.aws.amazon.com/amplify/create/repo-branch) 建立應用 (這裡使用 Amplify 提供的 [Next.js template](https://github.com/aws-samples/amplify-next-template) ,內含 Amplify CI/CD 流程) ![](https://i.imgur.com/XmYwclW.png) 2. 連結 Github 帳號與分支 ![](https://i.imgur.com/5Kg8FGP.png) 3. 基本設定 ![](https://i.imgur.com/Qo5Yeqa.png) 4. Review 確認後 deploy 就建立好專案了 ![](https://i.imgur.com/mAKT7yM.png) --- ### Data 設定 1. 在本地打開專案中的 **amplify/data/resource.ts** 更改資料結構 ![](https://i.imgur.com/0b3ipMg.png) ```javascript Settings: a // Settings 是資料庫名 .model({ key: a.string(), // 欄位 1 value: a.string(), // 欄位 2 }) .authorization((allow) => [allow.publicApiKey()]), ``` 2. commit 這筆修改,push 後 Amplify 就會自動開始部署 等部署完就可在 [AWS 管理後台](https://console.aws.amazon.com/amplify/apps) > 專案名 > 點進分支 > 資料 > 資料管理員 看到剛剛新增的資料表 settings 可以直接在這新增資料: ![](https://i.imgur.com/F3XPzf4.png) 3. 在本地讀取剛剛push完產生的設定檔: [AWS 管理後台](https://console.aws.amazon.com/amplify/apps) > 專案名 > 點進分支 > 點進最新的部署 > Deployed backend resources > 下載 amplify_outputs.json 檔 存在本地專案根目錄,即可在本地讀取該分支的資料表 (如果一直下載 amplify_outputs.json 沒更新,請用無痕模式下載) *或用指令部署到沙盒就可在本地操作沙盒資料表 `npx ampx sandbox` 4. 其他資料表操控與呼叫方法可參考 [Amplify Docs Gen2 - Data](https://docs.amplify.aws/nextjs/build-a-backend/data/) --- ### Authentication 設定 這個可以用來跟AWS的 Cognito 溝通,來製作登入註冊的功能 1. 原本模板的設定: 可自定義登入註冊需要的功能,然後 push 到遠端後 Amplify 會自動產生 Cognito 的 User Pool 和 Identity Pool ```typescript // amplify/auth/resource.ts import { defineAuth } from "@aws-amplify/backend"; export const auth = defineAuth({ loginWith: { email: true, }, }); ``` 2. 改成連結現有 Cognito (with backend) 需在[Cognito](https://ap-northeast-1.console.aws.amazon.com/cognito/)先建好 User Pool 和 Identity pool 因原本已有 User Pool,這邊只說明建立 App client 與 Identity pool流程: - App client : Cognito > User pools > App clients > Create app client 要使用SPA方式的,然後 Create ![Create app client](https://hackmd.io/_uploads/HJtNZi2Jex.png) ###### App client > Login pages > Edit > Allowed callback URLs, Allowed sign-out URLs 要填寫, 否則 amplify CLI跑不出 amplify_outputs.json - Identity pool : Cognito > Identity pools > Create identity pool Step 1 : 勾選Authenticated access, Guest access, Amazon Cognito user pool ![Step 1](https://hackmd.io/_uploads/BJ8Nfi21gx.png) Step 2 : 兩種都創新的 IAM role, 名稱結尾分別可用 authauthenticate 與 authauthenticatedU (這邊需要有AWS創立IAM的權限才能成功創建) ![Step 2](https://hackmd.io/_uploads/HyrRfi31xe.png) Step 3 : 連結到你的User pool跟App client (有下拉選單直接選擇) ![Step 3](https://hackmd.io/_uploads/rkx5Qi2yle.png) Step 4 : 命名 Identity pool ![Step 4](https://hackmd.io/_uploads/ryY5Ejnyxe.png) Step 5 : 確認資訊然後就創建完成了 ###### * Gen2 文件上有 without backend 的方式,但因已有用 backend 的方式連結 Data 了(如果用without會跟amplify_outputs.json打架),所以一樣用 with backend的方式連結現有 Cognito 3. 在各個 pool 中找到對應的資訊,把amplify/auth/resource.ts 改成以下: - userPoolClientId 在 User pools > 你的 pool > App clients - authRoleArn(Authenticated access) 和 unauthRoleArn(Guest access) 在 Identity pools > User access ```typescript import { referenceAuth } from "@aws-amplify/backend"; import * as dotenv from "dotenv"; /* 在本地 npx ampx sandbox 時, 這裡會讀不到環境變數,要用 dotenv, 然後可在 amplify 後台設環境變數 env=amplify */ if (process.env.ENV !== "amplify") { dotenv.config(); } export const auth = referenceAuth({ userPoolId: process.env.COGNITO_USER_POOL_ID!, userPoolClientId: process.env.COGNITO_USER_POOL_CLIENT_ID!, identityPoolId: process.env.COGNITO_IDENTITY_POOL_ID!, authRoleArn: process.env.COGNITO_AUTH_ROLE_ARN!, unauthRoleArn: process.env.COGNITO_UNAUTH_ROLE_ARN!, }); ``` ###### * env 變數資訊存在 AWS Amplify > 專案名 > Hosting: Environment variables, 在本地 npx ampx sandbox時讀不到 .env.local的變數 4. 然後跟 Data 設定一樣去 Amplify 控制台取得 amplify_outputs.json 設定檔,或部署到沙盒就可在本地操作沙盒資料 `npx ampx sandbox` 5. 登入註冊相關 API使用方式可參考 [Amplify Docs Gen2 - Authentication](https://docs.amplify.aws/gen2/build-a-backend/auth) ---- ### 登入註冊API注意事項 - 建立 User pool 時就要選擇使用哪種方式為帳號識別(email,phone,username),如果要修改就要重建 User pool,例如已經選擇為 email 的話,使用註冊 API 時,email 就會是必填選項 - 註冊時的驗證方式選擇在 Cognito > Sign-up > Attribute verification and user account confirmation 設定 - resendSignUpCode, resetPassword, sendUserAttributeVerificationCode 在短時間內最多只能打 5 次 - Passkey 要對到所使用的 domain 才起作用 User pools > auth.ohread.com > Authentication methods > Passkey > Domain for relying party ID - 有設定 MFA 的話,Passkey 登入會失敗,兩者不能同時存在 ---- ### Amplify build output 限制 220MB 要注意的是,Amplify 的 build output 不能超過 220 MB。 #### [檢查 amplify 部署 build ouput 大小:](https://docs.aws.amazon.com/amplify/latest/userguide/troubleshooting-SSR.html#build-output-too-large) 可於 terminal 執行檢查 build output 結構(job-id 為第幾個 Deploy,例如 Deploy20 的 job-id 為 20) ``` aws amplify get-job --app-id abcd1234 --branch-name main --job-id 2 ``` 執行後找到 `stepName: "BUILD"` 區塊中的 artifactUrl 輸入瀏覽器下載 build output 資料夾 - [Amplify 部署規範](https://docs.aws.amazon.com/zh_cn/amplify/latest/userguide/ssr-deployment-specification.html) - [Github issue](https://github.com/aws-amplify/amplify-hosting/issues/3647) - [Github issue](https://github.com/aws-amplify/amplify-hosting/issues/3863) - [Github issue](https://github.com/alexnguyennz/astro-aws-amplify/issues/23) ---- ### 使用 Amplify Auth 遇到的狀況 1. referenceAuth 不支援 Custom Domain [相關討論](https://github.com/aws-amplify/amplify-backend/issues/2350) referenceAuth 轉出的 `amplify_outputs.json` (auth.oauth.domain 裡只讀得到 cognito domain )讀不到 Custom Domain,所以要自己設定在 config 裡 ```typescript const outputs = JSON.parse(JSON.stringify(originalOutputs)); outputs.auth.oauth.domain = process.env.NEXT_PUBLIC_AUTH_DOMAIN; Amplify.configure(outputs); ``` 2. Passkey 、MFA不能同時存在 [官方說不會改這功能](https://repost.aws/questions/QU-DKBR1VdQQuRn-WZRFCMzg/cognito-passkey-login-without-email-username-and-with-mfa-enabled) 3. cognito設定 > App client > Login pages > Allowed callback URLs 一定要設兩個:localhost跟線上的callback網址,否則會出現redirect錯誤 (好像只有在使用Hosted UI的時候才會,用Managed login可以) 4. 遇到`User needs to set a password to sign in`可能的解法: * 匯入 user CVS 檔時 mfa_enabled 設定要留空 * 在 User Pool 按 Action>Reset password,讓使用者到登入頁走 signIn API 的 RESET_PASSWORD 流程 * 在 AWS CLI 重設 User 密碼 ```js aws cognito-idp admin-set-user-password \ --user-pool-id YOUR_USER_POOL_ID \ --username yourmail@gmail.com \ --password NEW_PASSWORD \ --permanent ``` 5. 只有 Managed login 能有 HttpOnly Cookie [相關連結](https://docs.amplify.aws/nextjs/build-a-backend/server-side-rendering/#authentication-with-nextjs-server-side-runtime) 自己做 layout+Amplify API 不能