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 React, { createContext, useEffect, useReducer } from "react";
|
||||
import { auth, getUserInfo } from "@/service/api/user.ts";
|
||||
import { getAuthToken, setAuthToken } from "@/hooks/useAuth.ts";
|
||||
import { getRoleByUsername } from "@/contexts/auth/role.ts";
|
||||
import React, {createContext, useEffect, useReducer} from "react";
|
||||
import {auth, getUserInfo} from "@/service/api/user.ts";
|
||||
import {getAuthToken, setAuthToken} from "@/hooks/useAuth.ts";
|
||||
import {getRoleByUsername} from "@/contexts/auth/role.ts";
|
||||
|
||||
|
||||
const AuthContext = createContext<AuthContextType | null>(null)
|
||||
|
||||
const initialState: AuthProps = {
|
||||
isLoggedIn: false,
|
||||
isInitialized: false,
|
||||
user: null
|
||||
isLoggedIn: false,
|
||||
isInitialized: false,
|
||||
user: null
|
||||
};
|
||||
const authReducer = (state: AuthProps, action: { action?: string, payload: Partial<AuthProps> }) => {
|
||||
return {
|
||||
...state,
|
||||
...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;
|
||||
// }
|
||||
return {
|
||||
...state,
|
||||
...action.payload,
|
||||
}
|
||||
}
|
||||
|
||||
const UserRoleStorageKey = 'user-current-role';
|
||||
|
||||
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) {
|
||||
localStorage.setItem(UserRoleStorageKey, role)
|
||||
localStorage.setItem(UserRoleStorageKey, role)
|
||||
}
|
||||
|
||||
function removeRoleStorage() {
|
||||
localStorage.removeItem(UserRoleStorageKey)
|
||||
localStorage.removeItem(UserRoleStorageKey)
|
||||
}
|
||||
|
||||
export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
const [state, dispatch] = useReducer(authReducer, initialState);
|
||||
function getInitUserData(user: UserProfile) {
|
||||
const {roles} = user;
|
||||
const role = !roles || roles.length === 0 ? 'staff' : (
|
||||
roles.includes('root') ? 'root' : (
|
||||
roles.includes('fo') ? 'fo' : 'ro'
|
||||
)
|
||||
) as UserRole
|
||||
|
||||
// MOCK INIT DATA
|
||||
const init = async () => {
|
||||
const token = getAuthToken();
|
||||
if (!token) {
|
||||
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);
|
||||
return {
|
||||
...user,
|
||||
origin_role: role,
|
||||
role: role == 'root' ? (getCurrentRole(user.username) || role) : role
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
dispatch({
|
||||
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',
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
export const AuthProvider = ({children}: { children: React.ReactNode }) => {
|
||||
const [state, dispatch] = useReducer(authReducer, initialState);
|
||||
|
||||
const updateUser = async (user: Partial<UserProfile>) => {
|
||||
dispatch({
|
||||
action: 'updateUser',
|
||||
payload: {
|
||||
user: {
|
||||
...state.user,
|
||||
...user
|
||||
} as never,
|
||||
// MOCK INIT DATA
|
||||
const init = async () => {
|
||||
const token = getAuthToken();
|
||||
if (!token) {
|
||||
dispatch({
|
||||
payload: {
|
||||
isInitialized: true,
|
||||
}
|
||||
})
|
||||
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(() => {
|
||||
init().then(console.log)
|
||||
}, [])
|
||||
const updateUser = async (user: Partial<UserProfile>) => {
|
||||
dispatch({
|
||||
action: 'updateUser',
|
||||
payload: {
|
||||
user: {
|
||||
...state.user,
|
||||
...user
|
||||
} as never,
|
||||
|
||||
// 判断是否已经初始化
|
||||
if (state.isInitialized !== undefined && !state.isInitialized) {
|
||||
return <Loader />;
|
||||
}
|
||||
return (<AuthContext.Provider value={{
|
||||
...state,
|
||||
login, logout,
|
||||
mockLogin, updateUser
|
||||
}}>{children}</AuthContext.Provider>)
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
init().then(console.log)
|
||||
}, [])
|
||||
|
||||
// 判断是否已经初始化
|
||||
if (state.isInitialized !== undefined && !state.isInitialized) {
|
||||
return <Loader/>;
|
||||
}
|
||||
return (<AuthContext.Provider value={{
|
||||
...state,
|
||||
login, logout,
|
||||
mockLogin, updateUser
|
||||
}}>{children}</AuthContext.Provider>)
|
||||
}
|
||||
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;
|
||||
nbf: number;
|
||||
type: string;
|
||||
roles: UserRole[];
|
||||
role: UserRole;
|
||||
origin_role?: UserRole;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user