登錄訪問控制
- AuthRoute 鑒權路由組件實現思路
- 參照官網自己封裝AuthRoute 鑒權路由組件
- 實現修改登錄成功后的跳轉
概述
項目中的兩種類型的功能和兩種類型的頁面:
兩種功能:
- 登錄后才能進行操作(比如:獲取個人資料)
- 不需要登錄就可以操作(比如:獲取房屋列表)
兩種頁面:
- 需要登錄才能訪問(比如:個人中心頁)
- 不需要登錄即可訪問(比如:首頁)
對於需要登錄才能操作的功能使用 axios 攔截器 進行處理(比如:統一添加請求頭 authorization等)
對於需要登錄才能訪問的頁面使用 路由控制
功能處理-使用axios攔截器統一處理token
- 在api.js 中,添加請求攔截器 (API.interceptors.request.user())
- 獲取到當前請求的接口路徑(url)
- 判斷接口路徑,是否是以/user 開頭,並且不是登錄或注冊接口(只給需要的接口添加請求頭)
- 如果是,就添加請求頭Authorization
// 添加請求攔截器
API.interceptors.request.use(config => {
const { url } = config
// 判斷請求url路徑
if (
url.startsWith('/user') &&
!url.startsWith('/user/login') &&
!url.startsWith('/user/registered')
) {
// 添加請求頭
config.headers.Authorization = getToken()
}
return config
})
- 添加響應攔截器 (API.interceptors.response.use())
- 判斷返回值中的狀態碼
- 如果是400,標示token超時或異常,直接移除token
// 添加響應攔截器
API.interceptors.response.use(response => {
const { status } = response.data
if (status === 400) {
// 此時,說明 token 失效,直接移除 token 即可
removeToken()
}
return response
})
頁面處理-AuthRoute鑒權路由組件
實現原理
-
限制某個頁面只能在登陸的情況下訪問,但是在React路由中並沒有直接提供該組件,需要手動封裝,來實現登陸訪問控制(類似與Vue路由的導航守衛)
-
參數 react-router-dom的鑒權文檔
-
AuthRoute 組件實際上就是對原來Route組件做了一次包裝,來實現一些額外的功能
- 使用
-
render方法:render props模式,指定該路由要渲染的組件內容
-
Redirect組件:重定向組件,通過to屬性,指定要跳轉的路由信息
// 官網封裝的核心邏輯代碼
// ...rest 把之前的組件中傳遞的屬性原封不動傳遞過來
function PrivateRoute({ component: Component, ...rest }) {
return (
<Route
{...rest}
// render方法: render props模式,指定該路由要渲染的組件內容
render={props =>
// 判斷是否登陸,如果登陸,跳轉配置的component,如果沒有登陸,利用 Redirect組件來進行重定向
fakeAuth.isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login",
// 把當前的頁面路徑保存起來,方便用戶登錄后能夠跳回當前頁面
state: { from: props.location }
}}
/>
)
}
/>
);
}
封裝AuthRoute鑒權路由組件
- 在components目錄中創建AuthRoute/index.js 文件
- 創建組件AuthRoute並導出
- 在AuthRoute組件中返回Route組件(在Route基礎上做了一層包裝,用於實現自定義功能)
- 給Route組件,添加render方法,指定改組件要渲染的內容(類似與component屬性)
- 在render方法中,調用isAuth() 判斷是否登陸
- 如果登陸了,就渲染當前組件(通過參數component獲取到要渲染的組件,需要重命名)
- 如果沒有登陸,就重定向到登陸頁面,並且指定登陸成功后腰跳轉的頁面路徑
- 將AuthRoute組件接收到的props原樣傳遞給Route組件(保證與Route組件使用方式相同)
- 使用AuthRoute組件配置路由規則,驗證是否實現頁面的登陸訪問控制
const AuthRoute = ({ component: Component, ...rest }) => {
return (
<Route
{...rest}
render={props => {
const isLogin = isAuth()
if (isLogin) {
// 已登錄
// 將 props 傳遞給組件,組件中才能獲取到路由相關信息
return <Component {...props} />
} else {
// 未登錄
return (
<Redirect
to={{
pathname: '/login',
state: {
from: props.location
}
}}
/>
)
}
}}
/>
)
}
export default AuthRoute
修改登錄成功跳轉
- 登陸成功后,判斷是否需要跳轉到用戶想要訪問的頁面(判斷props.location.state 是否有值)
- 如果不需要,則直接調用history.go(-1) 返回上一頁
- 如果需要,就跳轉到from.pathname 指定的頁面(推薦使用replace方法模式,不是push)
// 表單的提交事件
handleSubmit: async (values, { props }) => {
...
if (status === 200) {
// 登錄成功
localStorage.setItem('hkzf_token', body.token)
/*
1 登錄成功后,判斷是否需要跳轉到用戶想要訪問的頁面(判斷 props.location.state 是否有值)。
2 如果不需要(沒有值),則直接調用 history.go(-1) 返回上一頁。
3 如果需要,就跳轉到 from.pathname 指定的頁面(推薦使用 replace 方法模式,而不是 push)。
*/
if (!props.location.state) {
// 此時,表示是直接進入到了該頁面,直接調用 go(-1) 即可
props.history.go(-1)
} else {
// replace: [home, map]
props.history.replace(props.location.state.from.pathname)
}
} else {
// 登錄失敗
Toast.info(description, 2, null, false)
}
}