手把手擼一個前後端分離Admin系統(一)由使用者登入而來的JWT鑑權以
01 - 由使用者登入而來的 JWT 鑑權,許可權管理
前言
當一個新手學習 React 想要找一個練手的專案,結果市面上開源的都是各種 TODO App,甚至於 Real World 系列也差強人意。付費課程大多也很難詳盡地講清楚方方面面。同時,Admin, dashboard 之類的中後臺的需求日愈旺盛,值得前端開發者多多關注。於是就有了的產生,本文是其系列文章手把手帶你擼一個前後端分離的 Admin 專案的開篇文章
誰適合食用?
- 想要掌握 JWT 鑑權,許可權管理(前後端)
- 想了解真實專案上線
- 不適合全棧
技術棧
本專案前端基於 CRA 搭建,技術棧涉及 es6+, react, react-router, react-redux(以及 redux-devTools, redux-thunk, react-persist 等中介軟體),axios 和 ant design of react,sass, CSS Module 等等,後端基於 nest-cli 搭建,技術棧涉及 , nest.js 及其中介軟體,mongodb, mongoose, rxjs 等等,運維涉及 MEAN 環境搭建(涉及到 Nginx 的偏多),PM2 部署 node 應用。
為什麼不用 antd pro
- 不喜歡 antd pro + umi + dva 的繫結(儘管它們很優秀)
- antd pro 內容太多,初學者拿來學習中後臺開發難以找到頭緒
- 從零打造一個 admin 系統,一點點最佳化處來,有成就感,也順手一些
為什麼使用 Nest.js
- 全面支援
- 基於 Express.js,方便使用其豐富的中介軟體生態
- 受 Angular 啟發的架構
while plenty of superb libraries, helpers, and tools exist for Node (and server-side JavaScript), none of them effectively solve the main problem of - Architecture. Nest provides an out-of-the-box application architecture which allows developers and teams to create highly testable, scalable, loosely coupled, and easily maintainable applications - By Nest.js Official
一分鐘瞭解 Nest.js 核心概念
熟悉 Angular 的朋友看下 Nest.js 官方的 Overview 就可以愉快地 CRUD 了,不熟悉的朋友瞭解一下幾點就可以了:
- 透過模組樹來組織應用結構
- controller, module, service 是 Nest 三劍客,是基礎要素,controller 負責處理入站請求,返回相應到客戶端,module 實現某功能封裝,把業務邏輯放到 service 裡進行處理,service 可以透過依賴注入到 controller 和其他 service 中去
- Express.js 是一個基於 middleware 的中介軟體,所以 Nest 也是。像 Guards, Filters, Interceptors 等等實際上都是 middleware,只是具有不用功能,且執行順序不同
學習 Nest Tips:
- 反覆閱讀,因為它的資料不算多
- 程式碼示例可以參考,搭配 Octotree 食用更佳,非常全面
- 遇到問題,可以依照 stackoverflow --> issues 區 —> Nest Discord 伺服器,尋找解決辦法
步驟
-
前後端專案初始化
# 強烈建議換源頭,同時安裝nrm方便切換registry # 建議安裝nvm,實現多版本node安裝 # 透過cra腳手架安裝 npx create-react-app admin-fe # 安裝nest li npm i -g @nestjs/cli # 建立新的專案 nest new admin-be
-
前端刪除包括 serviceWorker 在內的多餘檔案
-
前端
-
前端新增 Antd
因為 antd v3 中打包會把所有圖示都搭進去,造成 bundle 會特別大,所以建議安裝 v4 版本,從 v3 升級到 v4 讓人一言難盡。
-
前端使用 reset-css 重置樣式,樣式方案選擇 Sass + CSS module
關於 react 的樣式方案有很多,Vanilla Css, CSS module, Css in JS,選擇 CSS module 的原因是使用非常簡單,可以看這篇文章 -
前端路由分類以及實際應用
根據 react-router 官方的說法,他們把前端路由分為 Static Routing 和 如下:
In these frameworks, you declare your routes as part of your app’s initialization before any rendering takes place.
所以,Static Routing 指的是在 rendering 發生前定義 routes,給個 express.js 示例:
```
app.get("/", handleIndex);
app.get("/invoices", handleInvoices);
app.get("/invoices/:id", handleInvoice);
app.get("/invoices/:id/edit", handleInvoiceEdit);
app.listen();
```
Dynamic Routing 意味著 Router 作為元件存在,在 rendering 過程中生效,示例如下:
````
import { BrowserRouter as Router } from "react-router-dom";
ReactDOM.render(
<Router>
<App />
</Router>, el);
const App = () => (
<div>
<nav>
<Link to="/dashboard">Dashboard</Link>
</nav>
</div>
);
```
關於 Nested Routes 和 Responsive Routes,動態路由都有非常好的表現。如果使用過 umijs 的朋友都會知道,umi 中支援配置式路由和約定式路由,其中配置式路由也就是動態路由,只不過把 router config 抽出到一個單獨的 js 檔案中,約定式路由也叫檔案路由,就是不需要手寫配置,檔案系統即路由,透過目錄和檔案及其命名分析出路由配置,應該是借鑑了 next.js 的。
-
建立路由配置檔案 router.config.js
import React from "react"; import { Link } from "react-router-dom"; import Loadable from "react-loadable"; import Loading from "./Loading"; // 使用react-Loadable來做程式碼拆分 const Home = Loadable({ loader: () => import("pages/Home/Home"), loading: Loading, delay: 300 }); const Charts = Loadable({ loader: () => import("pages/Charts/Charts"), loading: Loading, delay: 300 }); ...
為什麼使用 react-Loadabl 而不用 suspense, lazy 做 code splitting?使用 suspense,當網速足夠快, 資料立馬就獲取到了,頁面會閃一下,這是因為載入 loading 了,而maxDuration 屬性只有在 Concurrent Mode下才能使用
-
前端配置路由守衛
// src/router/RouteGuard.jsx import React from "react"; import { Route, Redirect, useLocation } from "react-router-dom"; import { checkPermission } from "./checkPermission"; function PrivateRoute({ children, ...rest }) { let location = useLocation(); let { isAuth, definedRoles } = { ...rest }; // 許可權不足跳轉(已登入) checkPermission(isAuth, definedRoles, location.pathname); // 未認證跳轉 return ( <Route {...rest} render={({ location }) => isAuth ? ( children ) : ( <Redirect to={{ pathname: "/login", state: { from: location } }} /> ) } /> ); } export default PrivateRoute; // src/router/checkPermission.js import React from "react"; import { Redirect } from "react-router-dom"; import { getRoles } from "utils/storage"; export const checkPermission = (isAuth, definedRoles, pathname) => { if (isAuth && getAuthorizedState(definedRoles, pathname)) { return <Redirect to={{ pathname: "/not-allow" }} />; } }; const getAuthorizedState = (definedRoles, pathname) => { // 不需要認證路徑 const isNotAuthedPath = ["/login", "/not-found", "/not-allow"].find( path => path === pathname ); let roles = getRoles() || []; // 條件為認證路徑下,前端獲取的roles陣列非空,並且包含在路由定義的陣列中 return ( !isNotAuthedPath && (!roles || !roles.every(role => !!definedRoles.find(item => item === role))) ) };
-
使用者註冊
// user.controller.ts 處理/user/signup的POST請求 import { Controller, Post } from '@nestjs/common'; @Controller('user') export class UserController { // 註冊 @Post("signup") async signup(@Body() Body) { const data = await this.userService.createUser(Body); return data; } } // user.service.ts 註冊邏輯 export class UserService { constructor( @InjectModel("User") private readonly userModel: Model<User> ){} // 註冊處理邏輯 async createUser(userDto: UserDto): Promise<any> { const { username, password, roles = ["user"], isEnabled = false } = userDto; // 從mongodb根據username查詢user const user = await this.findUser(username); console.log("user", user); // 驗證使用者是否存在(不能為admin) if (user) { throw new HttpException( { status: HttpStatus.FORBIDDEN, error: "使用者已經存在" }, 403 ); } else if (username === "admin") { throw new HttpException( { status: HttpStatus.FORBIDDEN, error: "無權註冊admin" }, 403 ); } // 給使用者加密 const hashPwd = await this.encryptService.getEncrypted(password); // 建立user(admin使用者此方法無法建立) const newUser = new this.userModel({ username: username, password: hashPwd, roles: roles, isEnabled: isEnabled }); await newUser.save(); return `註冊${username}成功!`; } }
使用者登入流程圖
應用上線流程圖
未完待續,有空繼續補上…
參考文件
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2459/viewspace-2825242/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- larke-admin 是一套使用 Laravel 8 、JWT 和 RBAC鑑權的前後端分離的通用後臺管理系統LaravelJWT後端
- jwt與session的登入鑑權JWTSession
- go-admin 基於 Gin + Vue + Element UI 的前後端分離許可權管理系統GoVueUI後端
- 實戰!Spring Boot Security+JWT前後端分離架構登入認證!Spring BootJWT後端架構
- 實戰!spring Boot security+JWT 前後端分離架構認證登入!Spring BootJWT後端架構
- JWT登入鑑權:避免在使用者操作的過程中JWT到期跳轉登入JWT
- 一場由React引發的前後端分離架構的思考React後端架構
- 新冠-物資管理系統,前後端分離系統 Vue+SpringBoot+JWT+Shiro ,作為一個練手專案.後端VueSpring BootJWT
- 新出爐前後端分離後臺管理系統jishupu-admin,還熱乎後端
- 前後端分離使用 Token 登入解決方案後端
- 前後端分離之JWT(JSON Web Token)的使用後端JWTJSONWeb
- Spring Security OAuth2.0認證授權六:前後端分離下的登入授權SpringOAuth後端
- 手把手教你使用 Spring Boot 3 開發上線一個前後端分離的生產級系統(一) - 介紹Spring Boot後端
- springBoot整合spring security+JWT實現單點登入與許可權管理前後端分離--築基中期Spring BootJWT後端
- 基於 Spring Security 的前後端分離的許可權控制系統Spring後端
- 前後端分離下的第三方登入後端
- 前後端分離Java統一響應返回格式後端Java
- Vue微信授權登入前後端分離較為優雅的解決方案Vue後端
- 企業管理系統前後端分離架構設計 系列一 許可權模型篇後端架構模型
- 前後端分離Ajax入門後端
- lenve/vhr: 微人事是一個前後端分離的人力資源管理系統後端
- 一個Java程式猿眼中的前後端分離以及Vue.js入門Java後端Vue.js
- 讓我大吃一塹的前後分離 web 站模擬登入Web
- SpringBoot+Vue前後端分離系統搭建Spring BootVue後端
- 開發一個大型後臺管理系統,應該用前後端分離的技術方案嗎?後端
- Catchadmin 基於 Tp6 的 前後端分離後臺管理許可權系統後端
- BS系統的登入鑑權流程演變
- SpringBoot+vue 前後端的分離專案筆記 [二] 使用者登入驗證Spring BootVue後端筆記
- eh-admin一套前後端一體的輕量級後臺管理系統後端
- 前後端分離之Ajax入門後端
- 分享一個在前後端分離的管理後臺專案中,如何方便的由後端來配置 Vue Router 的方案後端Vue
- Spring Security 前後端分離登入,非法請求直接返回 JSONSpring後端JSON
- 三分鐘做一個前後端系統,bee 做到了後端
- Laravel 5.5 不同使用者表登入認證 (前後臺分離)Laravel
- SpringBoot 2.x 開發案例之前後端分離鑑權Spring Boot後端
- 一個很 low 的 Python+Vue 前後端分離的介面平臺PythonVue後端
- 一次前後端分離架構的實踐後端架構
- 前後端分離專案OAuth第三方登入怎麼做(以Github舉例)後端OAuthGithub