Reactjs 用于oidc客户端的自定义React挂钩';t在第二次渲染时触发

Reactjs 用于oidc客户端的自定义React挂钩';t在第二次渲染时触发,reactjs,react-hooks,Reactjs,React Hooks,我正在使用获取当前用户名的自定义react钩子。它在第一次渲染和加载页面时工作,但不幸的是,当我导航回页面时,我的名为的自定义挂钩通过路由器变为空。我还尝试使用历史记录,但仍然无法获取名称 这是我的定制钩子 export function useUserAuthData() { const [name, setName] = useState("") async function populateData() { const [isAuthe

我正在使用获取当前用户名的自定义react钩子。它在第一次渲染和加载页面时工作,但不幸的是,当我导航回页面时,我的名为的自定义挂钩通过路由器变为空。我还尝试使用
历史记录
,但仍然无法获取名称

这是我的定制钩子

export function useUserAuthData() {
    const [name, setName] = useState("")

    async function populateData() {
        const [isAuthenticated, user] = await Promise.all([authService.isAuthenticated(), authService.getUser()])
        setName(user && user.name)
    }

    useEffect(() => {
        const subscriptionId = authService.subscribe(() => populateState())
        populateState()
        return () => {
            authService.unsubscribe(subscriptionId);
        }
    }, [])

    return { name }
}
我的用法是:

// my custom hook
const { name } = useUserAuthData()
下面是ASP.NET Core React SPA模板生成的
authService
,该模板使用
oidc客户端
(仅供参考)

从“oidc客户端”导入{UserManager,WebStorage StateStore};
从“/ApiAuthorizationConstants”导入{ApplicationPath,ApplicationName};
出口类服务{
_回调=[];
_nextSubscriptionId=0;
_user=null;
_isAuthenticated=false;
//默认情况下,弹出窗口被禁用,因为它们在Edge上无法正常工作。
//如果要启用弹出式身份验证,只需将此标志设置为false。
_popUpDisabled=true;
异步isAuthenticated(){
const user=wait this.getUser();
返回!!用户;
}
异步getUser(){
if(this.\u user&&this.\u user.profile){
返回此。\u user.profile;
}
等待此消息。ensureUserManagerInitialized();
const user=wait this.userManager.getUser();
返回用户&&user.profile;
}
异步getAccessToken(){
等待此消息。ensureUserManagerInitialized();
const user=wait this.userManager.getUser();
返回用户&&user.access\u令牌;
}
//我们尝试以三种不同的方式对用户进行身份验证:
//1)我们尝试查看是否可以对用户进行静默身份验证。这种情况会发生
//当用户已登录IdP并使用隐藏的iframe完成时
//在客户机上。
//2)我们尝试使用弹出窗口对用户进行身份验证。如果存在
//弹出窗口阻止程序或用户已禁用弹出窗口。
//3)如果上述两种方法失败,我们将浏览器重定向到IdP以执行传统的
//重定向流。
异步登录(状态){
等待此消息。ensureUserManagerInitialized();
试一试{
const silentUser=等待this.userManager.signisent(this.createArguments());
此.updateState(silentUser);
返回此。成功(状态);
}捕获(silentError){
//用户可能未通过身份验证,请退回到弹出式身份验证
log(“静默身份验证错误:”,silentError);
试一试{
如果(此按钮已禁用){
抛出新错误('Popup disabled.将'AuthorizeService.js:AuthorizeService.\u popupDisabled\'更改为false以启用它。“)
}
const popupuuser=等待this.userManager.signinpup(this.createArguments());
此.updateState(popupuuser);
返回此。成功(状态);
}捕获(popUpError){
如果(PopuperError.message==“弹出窗口关闭”){
//用户通过关闭打开的弹出窗口明确取消登录操作。
返回此.error(“用户关闭了窗口”);
}否则,如果(!this.\u popUpDisabled){
log(“弹出身份验证错误:”,popUpError);
}
//用户可能会阻止弹出窗口,请回退以重定向
试一试{
等待this.userManager.signInDirect(this.createArguments(state));
返回这个.redirect();
}捕获(重定向错误){
log(“重定向身份验证错误:”,重定向错误);
返回此.error(重定向错误);
}
}
}
}
异步完成信号(url){
试一试{
等待此消息。ensureUserManagerInitialized();
const user=wait this.userManager.signinCallback(url);
此.updateState(用户);
console.log(用户)
返回this.success(user&&user.state);
}捕获(错误){
console.log('登录时出错:',错误);
返回此.error('登录时出错');
}
}
//我们尝试以两种不同的方式注销用户:
//1)我们尝试使用弹出窗口进行注销。如果出现错误,此操作可能会失败
//弹出窗口阻止程序或用户已禁用弹出窗口。
//2)如果上述方法失败,我们将浏览器重定向到IdP以执行传统的
//注销后重定向流。
异步签出(状态){
等待此消息。ensureUserManagerInitialized();
试一试{
如果(此按钮已禁用){
抛出新错误('Popup disabled.将'AuthorizeService.js:AuthorizeService.\u popupDisabled\'更改为false以启用它。“)
}
等待this.userManager.signOutpupp(this.createArguments());
本协议不动产(未定义);
返回此。成功(状态);
}捕获(popupSignOutError){
log(“弹出签出错误:,popupSignOutError”);
试一试{
等待this.userManager.signoutRedirect(this.createArguments(state));
返回这个.redirect();
}捕获(重定向信号输出错误){
log(“重定向签出错误:”,redirectSignOutError);
返回此错误(重定向SignOutError);
}
}
}
异步完成信号输出(url){
等待此消息。ensureUserManagerInitialized();
试一试{
const response=wait this.userManager.signoutCallback(url);
此.updateState(null);
返回this.success(response&&response.data);
}捕获(错误){
log(`尝试注销'${error}'时出错');
返回此.error(error);
}
}
import { UserManager, WebStorageStateStore } from 'oidc-client';
import { ApplicationPaths, ApplicationName } from './ApiAuthorizationConstants';

export class AuthorizeService {
    _callbacks = [];
    _nextSubscriptionId = 0;
    _user = null;
    _isAuthenticated = false;

    // By default pop ups are disabled because they don't work properly on Edge.
    // If you want to enable pop up authentication simply set this flag to false.
    _popUpDisabled = true;

    async isAuthenticated() {
        const user = await this.getUser();
        return !!user;
    }

    async getUser() {
        if (this._user && this._user.profile) {
            return this._user.profile;
        }

        await this.ensureUserManagerInitialized();
        const user = await this.userManager.getUser();
        return user && user.profile;
    }

    async getAccessToken() {
        await this.ensureUserManagerInitialized();
        const user = await this.userManager.getUser();
        return user && user.access_token;
    }

    // We try to authenticate the user in three different ways:
    // 1) We try to see if we can authenticate the user silently. This happens
    //    when the user is already logged in on the IdP and is done using a hidden iframe
    //    on the client.
    // 2) We try to authenticate the user using a PopUp Window. This might fail if there is a
    //    Pop-Up blocker or the user has disabled PopUps.
    // 3) If the two methods above fail, we redirect the browser to the IdP to perform a traditional
    //    redirect flow.
    async signIn(state) {
        await this.ensureUserManagerInitialized();
        try {
            const silentUser = await this.userManager.signinSilent(this.createArguments());
            this.updateState(silentUser);
            return this.success(state);
        } catch (silentError) {
            // User might not be authenticated, fallback to popup authentication
            console.log("Silent authentication error: ", silentError);

            try {
                if (this._popUpDisabled) {
                    throw new Error('Popup disabled. Change \'AuthorizeService.js:AuthorizeService._popupDisabled\' to false to enable it.')
                }

                const popUpUser = await this.userManager.signinPopup(this.createArguments());
                this.updateState(popUpUser);
                return this.success(state);
            } catch (popUpError) {
                if (popUpError.message === "Popup window closed") {
                    // The user explicitly cancelled the login action by closing an opened popup.
                    return this.error("The user closed the window.");
                } else if (!this._popUpDisabled) {
                    console.log("Popup authentication error: ", popUpError);
                }

                // PopUps might be blocked by the user, fallback to redirect
                try {
                    await this.userManager.signinRedirect(this.createArguments(state));
                    return this.redirect();
                } catch (redirectError) {
                    console.log("Redirect authentication error: ", redirectError);
                    return this.error(redirectError);
                }
            }
        }
    }

    async completeSignIn(url) {
        try {
            await this.ensureUserManagerInitialized();
            const user = await this.userManager.signinCallback(url);
            this.updateState(user);
            console.log(user)
            return this.success(user && user.state);
        } catch (error) {
            console.log('There was an error signing in: ', error);
            return this.error('There was an error signing in.');
        }
    }

    // We try to sign out the user in two different ways:
    // 1) We try to do a sign-out using a PopUp Window. This might fail if there is a
    //    Pop-Up blocker or the user has disabled PopUps.
    // 2) If the method above fails, we redirect the browser to the IdP to perform a traditional
    //    post logout redirect flow.
    async signOut(state) {
        await this.ensureUserManagerInitialized();
        try {
            if (this._popUpDisabled) {
                throw new Error('Popup disabled. Change \'AuthorizeService.js:AuthorizeService._popupDisabled\' to false to enable it.')
            }

            await this.userManager.signoutPopup(this.createArguments());
            this.updateState(undefined);
            return this.success(state);
        } catch (popupSignOutError) {
            console.log("Popup signout error: ", popupSignOutError);
            try {
                await this.userManager.signoutRedirect(this.createArguments(state));
                return this.redirect();
            } catch (redirectSignOutError) {
                console.log("Redirect signout error: ", redirectSignOutError);
                return this.error(redirectSignOutError);
            }
        }
    }

    async completeSignOut(url) {
        await this.ensureUserManagerInitialized();
        try {
            const response = await this.userManager.signoutCallback(url);
            this.updateState(null);
            return this.success(response && response.data);
        } catch (error) {
            console.log(`There was an error trying to log out '${error}'.`);
            return this.error(error);
        }
    }

    updateState(user) {
        this._user = user;
        this._isAuthenticated = !!this._user;
        this.notifySubscribers();
    }

    subscribe(callback) {
        this._callbacks.push({ callback, subscription: this._nextSubscriptionId++ });
        return this._nextSubscriptionId - 1;
    }

    unsubscribe(subscriptionId) {
        const subscriptionIndex = this._callbacks
            .map((element, index) => element.subscription === subscriptionId ? { found: true, index } : { found: false })
            .filter(element => element.found === true);
        if (subscriptionIndex.length !== 1) {
            throw new Error(`Found an invalid number of subscriptions ${subscriptionIndex.length}`);
        }

        this._callbacks.splice(subscriptionIndex[0].index, 1);
    }

    notifySubscribers() {
        for (let i = 0; i < this._callbacks.length; i++) {
            const callback = this._callbacks[i].callback;
            callback();
        }
    }

    createArguments(state) {
        return { useReplaceToNavigate: true, data: state };
    }

    error(message) {
        return { status: AuthenticationResultStatus.Fail, message };
    }

    success(state) {
        return { status: AuthenticationResultStatus.Success, state };
    }

    redirect() {
        return { status: AuthenticationResultStatus.Redirect };
    }

    async ensureUserManagerInitialized() {
        if (this.userManager !== undefined) {
            return;
        }

        let response = await fetch(ApplicationPaths.ApiAuthorizationClientConfigurationUrl);
        if (!response.ok) {
            throw new Error(`Could not load settings for '${ApplicationName}'`);
        }

        let settings = await response.json();
        settings.automaticSilentRenew = true;
        settings.includeIdTokenInSilentRenew = true;
        settings.userStore = new WebStorageStateStore({
            prefix: ApplicationName
        });

        this.userManager = new UserManager(settings);

        this.userManager.events.addUserSignedOut(async () => {
            await this.userManager.removeUser();
            this.updateState(undefined);
        });
    }

    static get instance() { return authService }
}

const authService = new AuthorizeService();

export default authService;

export const AuthenticationResultStatus = {
    Redirect: 'redirect',
    Success: 'success',
    Fail: 'fail'
};