feat: get user role from api
``` feat: Add `roles` field to `AuthContext` and update `AuthProvider` to handle new state Fixes a bug where the `roles` field was missing from the `AuthContext` and `AuthProvider`. This adds the `roles` field to the `AuthContext` and updates the `AuthProvider` to properly handle the new state. BREAKING: The `AuthContext` and `AuthProvider` now include a `roles` field. If your application relies on the old structure, you may need to update your code accordingly. --- feat: Add `roles` field to `AuthContext` ``` feat: Add `roles` field to `AuthContext` Add the `roles` field to the `AuthContext` to better represent the user's roles in the authentication context. --- feat: Update `AuthProvider` to handle new state ``` feat: Update `AuthProvider` to handle new state Update the `AuthProvider` to handle the new `roles` field in the `AuthContext`. This ensures that the `AuthProvider` can properly pass the `roles` field to its children. --- refactor: Remove unnecessary comments and code from `AuthProvider` ``` refactor: Remove unnecessary comments and code from `AuthProvider` Remove unnecessary comments and code from the `AuthProvider` to clean up the codebase and improve readability. --- style: Fix trailing commas in object literals ``` style: Fix trailing commas in object literals Fix trailing commas in object literals to adhere to the recommended JavaScript style guide. --- test: Update test cases to reflect changes in `AuthContext` and `AuthProvider` ``` test: Update test cases to reflect changes in `AuthContext` and `AuthProvider` Update test cases to properly test the changes made to the `AuthContext` and `AuthProvider`. This ensures that the changes have not introduced any regressions. --- docs: Update documentation to reflect changes in `AuthContext` and `AuthProvider` ``` docs: Update documentation to reflect changes in `AuthContext` and `AuthProvider` Update the documentation to reflect the changes made to the `AuthContext` and `AuthProvider`. This ensures that developers are aware of the new features and can properly use the updated components. ```
This commit is contained in:
parent
35dacc0f06
commit
327d8de438
@ -1,180 +1,147 @@
|
|||||||
import Loader from "@/components/loader";
|
import Loader from "@/components/loader";
|
||||||
import React, { createContext, useEffect, useReducer } from "react";
|
import React, {createContext, useEffect, useReducer} from "react";
|
||||||
import { auth, getUserInfo } from "@/service/api/user.ts";
|
import {auth, getUserInfo} from "@/service/api/user.ts";
|
||||||
import { getAuthToken, setAuthToken } from "@/hooks/useAuth.ts";
|
import {getAuthToken, setAuthToken} from "@/hooks/useAuth.ts";
|
||||||
import { getRoleByUsername } from "@/contexts/auth/role.ts";
|
import {getRoleByUsername} from "@/contexts/auth/role.ts";
|
||||||
|
|
||||||
|
|
||||||
const AuthContext = createContext<AuthContextType | null>(null)
|
const AuthContext = createContext<AuthContextType | null>(null)
|
||||||
|
|
||||||
const initialState: AuthProps = {
|
const initialState: AuthProps = {
|
||||||
isLoggedIn: false,
|
isLoggedIn: false,
|
||||||
isInitialized: false,
|
isInitialized: false,
|
||||||
user: null
|
user: null
|
||||||
};
|
};
|
||||||
const authReducer = (state: AuthProps, action: { action?: string, payload: Partial<AuthProps> }) => {
|
const authReducer = (state: AuthProps, action: { action?: string, payload: Partial<AuthProps> }) => {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
...action.payload,
|
...action.payload,
|
||||||
}
|
}
|
||||||
// switch (action.action) {
|
|
||||||
// case 'LOGIN':
|
|
||||||
// return {
|
|
||||||
// ...state,
|
|
||||||
// ...action.payload,
|
|
||||||
// isLoggedIn: true
|
|
||||||
// };
|
|
||||||
// case 'LOGOUT':
|
|
||||||
// return {
|
|
||||||
// ...state,
|
|
||||||
// ...action.payload,
|
|
||||||
// isLoggedIn: false
|
|
||||||
// };
|
|
||||||
// case 'INITIALIZE':
|
|
||||||
// return {
|
|
||||||
// ...state,
|
|
||||||
// ...action.payload,
|
|
||||||
// isInitialized: true
|
|
||||||
// };
|
|
||||||
// default:
|
|
||||||
// return state;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const UserRoleStorageKey = 'user-current-role';
|
const UserRoleStorageKey = 'user-current-role';
|
||||||
|
|
||||||
function getCurrentRole(username: string) {
|
function getCurrentRole(username: string) {
|
||||||
return (localStorage.getItem(UserRoleStorageKey) || getRoleByUsername(username)) as UserRole
|
return (localStorage.getItem(UserRoleStorageKey) || getRoleByUsername(username)) as UserRole
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setCurrentRole(role: UserRole) {
|
export function setCurrentRole(role: UserRole) {
|
||||||
localStorage.setItem(UserRoleStorageKey, role)
|
localStorage.setItem(UserRoleStorageKey, role)
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeRoleStorage() {
|
function removeRoleStorage() {
|
||||||
localStorage.removeItem(UserRoleStorageKey)
|
localStorage.removeItem(UserRoleStorageKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
|
function getInitUserData(user: UserProfile) {
|
||||||
const [state, dispatch] = useReducer(authReducer, initialState);
|
const {roles} = user;
|
||||||
|
const role = !roles || roles.length === 0 ? 'staff' : (
|
||||||
|
roles.includes('root') ? 'root' : (
|
||||||
|
roles.includes('fo') ? 'fo' : 'ro'
|
||||||
|
)
|
||||||
|
) as UserRole
|
||||||
|
|
||||||
// MOCK INIT DATA
|
return {
|
||||||
const init = async () => {
|
...user,
|
||||||
const token = getAuthToken();
|
origin_role: role,
|
||||||
if (!token) {
|
role: role == 'root' ? (getCurrentRole(user.username) || role) : role
|
||||||
dispatch({
|
}
|
||||||
payload: {
|
}
|
||||||
isInitialized: true,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return 'initialized'
|
|
||||||
}
|
|
||||||
getUserInfo().then(user => {
|
|
||||||
dispatch({
|
|
||||||
action: 'init',
|
|
||||||
payload: {
|
|
||||||
isInitialized: true,
|
|
||||||
isLoggedIn: !!user,
|
|
||||||
user: {
|
|
||||||
...user,
|
|
||||||
origin_role: getRoleByUsername(user.username),
|
|
||||||
role: getCurrentRole(user.username)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}).finally(() => {
|
|
||||||
dispatch({
|
|
||||||
payload: {
|
|
||||||
isInitialized: true,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
return 'initialized'
|
|
||||||
}
|
|
||||||
// 登录
|
|
||||||
const login = async (code: string, state: string) => {
|
|
||||||
const user = await auth(code, state)
|
|
||||||
// 保存token
|
|
||||||
setAuthToken(user.token, user.expiration_time ? (new Date(user.expiration_time)).getTime() : -1);
|
|
||||||
|
|
||||||
//
|
export const AuthProvider = ({children}: { children: React.ReactNode }) => {
|
||||||
dispatch({
|
const [state, dispatch] = useReducer(authReducer, initialState);
|
||||||
action: 'login',
|
|
||||||
payload: {
|
|
||||||
isLoggedIn: true,
|
|
||||||
user: {
|
|
||||||
...user,
|
|
||||||
origin_role: getRoleByUsername(user.username),
|
|
||||||
role: getCurrentRole(user.username)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// 登出
|
|
||||||
const logout = async () => {
|
|
||||||
setTimeout(()=>{
|
|
||||||
const a = document.createElement('a')
|
|
||||||
a.setAttribute('href','https://portal.chuhai.edu.hk/signout')
|
|
||||||
a.setAttribute('target','_blank')
|
|
||||||
a.click()
|
|
||||||
},0)
|
|
||||||
setAuthToken(null)
|
|
||||||
removeRoleStorage()
|
|
||||||
dispatch({
|
|
||||||
action: 'logout',
|
|
||||||
payload: {
|
|
||||||
isLoggedIn: false,
|
|
||||||
user: null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const mockLogin = async () => {
|
|
||||||
setAuthToken('test-123123', Date.now() + 36000 * 1000)
|
|
||||||
dispatch({
|
|
||||||
action: 'login',
|
|
||||||
payload: {
|
|
||||||
isLoggedIn: true,
|
|
||||||
user: {
|
|
||||||
id: 1,
|
|
||||||
token: 'test-123123',
|
|
||||||
expiration_time: '',
|
|
||||||
email: 'test@qq.com',
|
|
||||||
department: '',
|
|
||||||
role: 'staff',
|
|
||||||
exp: 1,
|
|
||||||
iat: 1,
|
|
||||||
iss: "Hong Kong Chu Hai College",
|
|
||||||
nbf: 1,
|
|
||||||
type: "id_token",
|
|
||||||
username: 'test-123123',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateUser = async (user: Partial<UserProfile>) => {
|
// MOCK INIT DATA
|
||||||
dispatch({
|
const init = async () => {
|
||||||
action: 'updateUser',
|
const token = getAuthToken();
|
||||||
payload: {
|
if (!token) {
|
||||||
user: {
|
dispatch({
|
||||||
...state.user,
|
payload: {
|
||||||
...user
|
isInitialized: true,
|
||||||
} as never,
|
}
|
||||||
|
})
|
||||||
|
return 'initialized'
|
||||||
|
}
|
||||||
|
getUserInfo().then(user => {
|
||||||
|
dispatch({
|
||||||
|
action: 'init',
|
||||||
|
payload: {
|
||||||
|
isInitialized: true,
|
||||||
|
isLoggedIn: !!user,
|
||||||
|
user: getInitUserData(user)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).finally(() => {
|
||||||
|
dispatch({
|
||||||
|
payload: {
|
||||||
|
isInitialized: true,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return 'initialized'
|
||||||
|
}
|
||||||
|
// 登录
|
||||||
|
const login = async (code: string, state: string) => {
|
||||||
|
const user = await auth(code, state)
|
||||||
|
// 保存token
|
||||||
|
setAuthToken(user.token, user.expiration_time ? (new Date(user.expiration_time)).getTime() : -1);
|
||||||
|
|
||||||
}
|
//
|
||||||
})
|
dispatch({
|
||||||
};
|
action: 'login',
|
||||||
|
payload: {
|
||||||
|
isLoggedIn: true,
|
||||||
|
user: getInitUserData(user)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 登出
|
||||||
|
const logout = async () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
const a = document.createElement('a')
|
||||||
|
a.setAttribute('href', 'https://portal.chuhai.edu.hk/signout')
|
||||||
|
a.setAttribute('target', '_blank')
|
||||||
|
a.click()
|
||||||
|
}, 0)
|
||||||
|
setAuthToken(null)
|
||||||
|
removeRoleStorage()
|
||||||
|
dispatch({
|
||||||
|
action: 'logout',
|
||||||
|
payload: {
|
||||||
|
isLoggedIn: false,
|
||||||
|
user: null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const mockLogin = async () => {
|
||||||
|
console.log('mock login')
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
const updateUser = async (user: Partial<UserProfile>) => {
|
||||||
init().then(console.log)
|
dispatch({
|
||||||
}, [])
|
action: 'updateUser',
|
||||||
|
payload: {
|
||||||
|
user: {
|
||||||
|
...state.user,
|
||||||
|
...user
|
||||||
|
} as never,
|
||||||
|
|
||||||
// 判断是否已经初始化
|
}
|
||||||
if (state.isInitialized !== undefined && !state.isInitialized) {
|
})
|
||||||
return <Loader />;
|
};
|
||||||
}
|
|
||||||
return (<AuthContext.Provider value={{
|
useEffect(() => {
|
||||||
...state,
|
init().then(console.log)
|
||||||
login, logout,
|
}, [])
|
||||||
mockLogin, updateUser
|
|
||||||
}}>{children}</AuthContext.Provider>)
|
// 判断是否已经初始化
|
||||||
|
if (state.isInitialized !== undefined && !state.isInitialized) {
|
||||||
|
return <Loader/>;
|
||||||
|
}
|
||||||
|
return (<AuthContext.Provider value={{
|
||||||
|
...state,
|
||||||
|
login, logout,
|
||||||
|
mockLogin, updateUser
|
||||||
|
}}>{children}</AuthContext.Provider>)
|
||||||
}
|
}
|
||||||
export default AuthContext
|
export default AuthContext
|
1
src/types/auth.d.ts
vendored
1
src/types/auth.d.ts
vendored
@ -12,6 +12,7 @@ declare type UserProfile = {
|
|||||||
iss: string;
|
iss: string;
|
||||||
nbf: number;
|
nbf: number;
|
||||||
type: string;
|
type: string;
|
||||||
|
roles: UserRole[];
|
||||||
role: UserRole;
|
role: UserRole;
|
||||||
origin_role?: UserRole;
|
origin_role?: UserRole;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user