亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 網站 > WEB開發 > 正文

【React全家桶入門之十】登錄與身份認證

2024-04-27 15:14:01
字體:
來源:轉載
供稿:網友

仔細想想,我們的后臺系統還沒有一個登錄功能,太不靠譜,趕緊把防盜門安上!

SPA的鑒權方式和傳統的web應用不同:由于頁面的渲染不再依賴服務端,與服務端的交互都通過接口來完成,而REASTful風格的接口提倡無狀態(state less),通常不使用cookie和session來進行身份認證。

比較流行的一種方式是使用web token,所謂的token可以看作是一個標識身份的令牌??蛻舳嗽诘卿洺晒罂梢垣@得服務端加密后的token,然后在后續需要身份認證的接口請求中在header中帶上這個token,服務端就可以通過判斷token的有效性來驗證該請求是否合法。

我們先來改造一下服務端,實現一個簡單的基于token的身份認證(可直接復制代碼,無需關心具體實現)。

改造服務端

先在根目錄下執行npm i json-server -D,雖然一開始以全局的方式安裝過json-server這個工具,但本次要在代碼中使用json-server的api,需要將其安裝為項目依賴。

然后新建/server/auth.js文件,寫入以下代碼:

const expireTime = 1000 * 60;module.exports = function (req, res, next) { res.header('access-Control-Expose-Headers', 'access-token'); const now = Date.now(); let unauthorized = true; const token = req.headers['access-token']; if (token) { const expired = now - token > expireTime; if (!expired) { unauthorized = false; res.header('access-token', now); } } if (unauthorized) { res.sendStatus(401); } else { next(); }};

新建/server/index.js文件,寫入以下代碼:

const path = require('path');const jsonServer = require('json-server');const server = jsonServer.create();const router = jsonServer.router(path.join(__dirname, 'db.json'));const middlewares = jsonServer.defaults();server.use(jsonServer.bodyParser);server.use(middlewares);server.post('/login', function (req, res, next) { res.header('Access-Control-Expose-Headers', 'access-token'); const {account, passWord} = req.body; if (account === 'admin' && password === '123456') { res.header('access-token', Date.now()); res.json(true); } else { res.json(false); }});server.use(require('./auth'));server.use(router);server.listen(3000, function () { console.log('JSON Server is running in http://localhost:3000');});

修改/package.json文件中的scripts.server

{ ... "scripts": { "server": "node server/index.js", ... }, ...}

然后使用npm run server重啟服務器。

現在我們的服務器就擁有了身份認證的功能,訪問除了’/login’外的其它接口時,服務端會根據請求的header中access-token來判斷請求是否有效,如果無效則會返回401狀態碼。

當客戶端收到401的狀態碼時,需要跳轉到登錄頁面進行登錄,有效的管理員賬號為admin,密碼為123456。

以POST方法提交下面的參數到’http://localhost:3000/login‘接口,就能夠完成登錄。

{ "account": "admin", "password": "123456"}

登錄成功后,接口返回true,并且在返回的headers中包含了一個有效的access-token,用于在后面的請求中使用;登錄失敗則返回false。

access-token的有效期為1分鐘,每次有效的接口請求都會獲得新的access-token;若1分鐘內沒有做操作,則會過期需要重新登錄。

我們的access-token只是一個簡單的timestamp,且沒有做任何加密措施。

封裝fetch

由于我們每個接口的請求都需要加上一個名為access-token的header,在每次需要調用接口的時候都寫一遍就非常的不明智了,所以我們需要封裝fetch方法。

新建/src/utils/request.js,寫入以下代碼:

import { hashHistory } from 'react-router';export default function request (method, url, body) { method = method.toUpperCase(); if (method === 'GET') { // fetch的GET不允許有body,參數只能放在url中 body = undefined; } else { body = body && JSON.stringify(body); } return fetch(url, { method, headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Access-Token': sessionStorage.getItem('access_token') // 從sessionStorage中獲取access token }, body }) .then((res) => { if (res.status === 401) { hashHistory.push('/login'); return request方法封裝了添加access-token頭等邏輯,然后就可以在需要調用接口的時候使用request或get、post等方法了,比如/src/components/BookEditor.js

...import request, {get} from '../utils/request';class BookEditor extends React.Component { ... handleSubmit (e) { ... let editType = '添加'; let apiUrl = 'http://localhost:3000/book'; let method = 'post'; if (editTarget) { ... } request(method, apiUrl, { name: name.value, price: price.value, owner_id: owner_id.value }) .then((res) => { if (res.id) { ... } else { ... } }) .catch((err) => console.error(err)); } getRecommendUsers (partialUserId) { get('http://localhost:3000/user?id_like=' + partialUserId) .then((res) => { if (res.length === 1 && res[0].id === partialUserId) { return; } ... }); } ...}...

其它還有/src/components/UserEditor.js、/src/pages/BookEdit.js、/src/pages/BookList.js、/src/pages/UserEdit.js/src/pages/UserList.js文件需要進行相應的修改。

實現登錄頁面

現在嘗試訪問一下用戶列表頁,發現表格里面并沒有數據,因為沒有登錄接口訪問被拒絕了并且嘗試跳轉到路由’/login’。

現在來實現一個登錄頁面組件,在/src/pages下新建Login.js文件;

import React from 'react';import HomeLayout from '../layouts/HomeLayout';import FormItem from '../components/FormItem';import { post } from '../utils/request';import formProvider from '../utils/formProvider';class Login extends React.Component { constructor () { super(); this.handleSubmit = this.handleSubmit.bind(this); } handleSubmit (e) { e.preventDefault(); const {formValid, form: {account, password}} = this.props; if (!formValid) { alert('請輸入賬號或密碼'); return; } post('http://localhost:3000/login', { account: account.value, password: password.value }) .then((res) => { if (res) { this.context.router.push('/'); } else { alert('登錄失敗,賬號或密碼錯誤'); } }) } render () { const {form: {account, password}, onFormChange} = this.props; return ( <HomeLayout title="請登錄"> <form onSubmit={this.handleSubmit}> <FormItem label="賬號:" valid={account.valid} error={account.error}> <input type="text" value={account.value} onChange={e => onFormChange('account', e.target.value)}/> </FormItem> <FormItem label="密碼:" valid={password.valid} error={password.error}> <input type="password" value={password.value} onChange={e => onFormChange('password', e.target.value)}/> </FormItem> <br/> <input type="submit" value="登錄"/> </form> </HomeLayout> ); }}Login.contextTypes = { router: React.PropTypes.object.isRequired};Login = formProvider({ account: { defaultValue: '', rules: [ { pattern (value) { return value.length > 0; }, error: '請輸入賬號' } ] }, password: { defaultValue: '', rules: [ { pattern (value) { return value.length > 0; }, error: '請輸入密碼' } ] }})(Login);export default Login;

登錄頁面組件和UserEditor或者BookEditor類似,都是一個表單。

在這里提交表單成功后跳轉到首頁。

最后,別忘了加上登錄頁面的路由。

最終效果


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
午夜欧美不卡精品aaaaa| 日韩精品视频在线观看免费| 欧美日韩在线观看视频| 宅男66日本亚洲欧美视频| 国产在线一区二区三区| 久久久亚洲影院你懂的| 午夜免费在线观看精品视频| 欧美性猛交视频| 亚洲精品国产综合久久| 成人黄色网免费| 色婷婷成人综合| 日韩高清av一区二区三区| 欧美福利视频在线| 色香阁99久久精品久久久| 国产91色在线|免| 欧美激情久久久久| 日韩精品999| 亚洲色无码播放| 91精品久久久久久久久久久久久久| 久久国产精品影片| 日韩亚洲综合在线| 国产精品jizz在线观看麻豆| 亚洲国产又黄又爽女人高潮的| 亚洲男人av电影| 福利精品视频在线| 欧洲亚洲妇女av| 欧美精品成人91久久久久久久| 精品偷拍一区二区三区在线看| 欧美大片欧美激情性色a∨久久| 亚洲美女免费精品视频在线观看| 国产不卡一区二区在线播放| 狠狠躁天天躁日日躁欧美| 日韩电影大全免费观看2023年上| 国产欧美精品久久久| 亚洲欧洲一区二区三区久久| 亚洲综合小说区| 国产在线久久久| 97视频在线免费观看| 日韩电影免费在线观看中文字幕| 精品国产1区2区| www.日本久久久久com.| 亚洲天堂影视av| 欧美激情日韩图片| 国产精品一区二区久久精品| 亚洲国产欧美在线成人app| 亚洲一区精品电影| 欧美电影免费在线观看| 日韩精品一区二区视频| 国产精品久久久久久久久久久新郎| 国内精品伊人久久| 亚洲美女在线视频| 欧美性69xxxx肥| 亚洲精品美女久久久| 欧美黄网免费在线观看| 日韩欧美一区二区三区久久| 久久久久久久一| 国产成人亚洲综合91精品| 91中文在线观看| 4444欧美成人kkkk| 国产精品99蜜臀久久不卡二区| 欧美成人免费播放| 欧美另类暴力丝袜| 成人综合网网址| 91在线观看免费观看| 亚洲电影免费观看高清完整版| 精品国产精品三级精品av网址| 97国产真实伦对白精彩视频8| 狠狠躁夜夜躁人人爽天天天天97| 久久久久久久久爱| 国产精品视频地址| 日本一区二区在线播放| 亚洲男人天堂久| 久久6免费高清热精品| 精品亚洲国产成av人片传媒| 日本久久久久久久久| 亚洲女人初尝黑人巨大| 亚洲bt欧美bt日本bt| 国产精品美女久久久久久免费| 欧美性极品少妇精品网站| 日韩免费观看视频| 久久99热精品这里久久精品| 午夜精品久久17c| 亚洲国产成人精品久久| 久久久噜噜噜久久久| 亚洲精品一区二三区不卡| 91精品久久久久久久久不口人| 伊人久久久久久久久久久| 欧美亚洲视频在线看网址| 欧美成aaa人片在线观看蜜臀| 亚洲sss综合天堂久久| 91久久精品久久国产性色也91| 色婷婷成人综合| 久久精品国产久精国产一老狼| 亚洲精品视频二区| 欧美日韩亚洲视频一区| 亚洲欧洲国产精品| 久久99国产精品自在自在app| 精品视频久久久久久久| 亚洲www在线| 欧美激情视频网址| 亚洲国产精品系列| 亚洲视频专区在线| 中文字幕日韩电影| 亚洲色图色老头| 欧美大片欧美激情性色a∨久久| 国产一区二区三区高清在线观看| 日韩视频免费在线| 亚洲电影免费观看高清完整版在线观看| 亚洲天堂精品在线| 欧美多人爱爱视频网站| 伊人伊成久久人综合网小说| 2019中文字幕全在线观看| 日韩精品视频观看| 日韩激情第一页| 国产成人久久精品| 97视频免费在线看| 国产成人jvid在线播放| 国产网站欧美日韩免费精品在线观看| 国产精品久久婷婷六月丁香| 欧美日韩国产中文精品字幕自在自线| 日韩欧美国产高清91| 欧美黄色小视频| 欧美性猛交xxxxx免费看| 国产精品劲爆视频| 日韩中文字幕第一页| www.欧美精品| 亚洲人成电影网站色| 大量国产精品视频| 亚洲男人7777| 欧美孕妇与黑人孕交| 成人黄色免费片| 欧美性xxxxxx| 2019日本中文字幕| 久久久99免费视频| 久久精品国产久精国产一老狼| 久久99热精品这里久久精品| 一道本无吗dⅴd在线播放一区| 亚洲国产美女久久久久| 午夜精品久久久久久久久久久久| 日韩精品欧美激情| 欧美xxxx综合视频| 欧美激情国产日韩精品一区18| 亚洲视频电影图片偷拍一区| 成人在线国产精品| 日韩电影免费在线观看中文字幕| 日韩精品久久久久久久玫瑰园| 欧美日韩成人黄色| 亚洲色图校园春色| 欧美中文在线观看国产| 97精品一区二区三区| 久热精品视频在线| 91亚洲精华国产精华| 国产精品人成电影在线观看| 欧美日韩在线视频一区| 色青青草原桃花久久综合| 日韩天堂在线视频| 亚洲欧美国内爽妇网| 欧美疯狂xxxx大交乱88av| 69**夜色精品国产69乱| 亚洲精品黄网在线观看| 日韩经典中文字幕在线观看| 久久影视电视剧免费网站| 精品视频—区二区三区免费| 亚洲欧美日韩一区二区三区在线|