检查角色时出现无限循环.VueJS [英] Infinite loop when checking roles. VueJS

查看:60
本文介绍了检查角色时出现无限循环.VueJS的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有一个导航栏,其中根据用户角色显示元素:

There is a navigation bar where elements are displayed depending on the user's role:

<b-navbar-toggle
    right
    class="jh-navbar-toggler d-lg-none"
    href="javascript:void(0);"
    data-toggle="collapse"
    target="header-tabs"
    aria-expanded="false"
    aria-label="Toggle navigation">
  <font-awesome-icon icon="bars"/>
</b-navbar-toggle>

<b-collapse is-nav id="header-tabs">
  <b-navbar-nav class="ml-auto">
    <b-nav-item-dropdown
        right
        id="pass-menu"
        v-if="hasAnyAuthority('ROLE_USER') && authenticated"
        :class="{'router-link-active': subIsActive('/pass')}"
        active-class="active"
        class="pointer">
                <span slot="button-content" class="navbar-dropdown-menu">
                    <font-awesome-icon icon="ticket-alt"/>
                    <span>First element</span>
                </span>
    </b-nav-item-dropdown>

    <b-nav-item-dropdown
        right
        id="dictionaries-menu"
        v-if="hasAnyAuthority('ROLE_ADMIN') && authenticated"
        :class="{'router-link-active': subIsActive('/dictionary')}"
        active-class="active"
        class="pointer">
                <span slot="button-content" class="navbar-dropdown-menu">
                    <font-awesome-icon icon="book"/>
                    <span>Second element</span>
                </span>
    </b-nav-item-dropdown>
  </b-navbar-nav>

如果我为两个元素设置了相同的角色,例如 ROLE_USER ,则一切正常.但是,当两个元素的角色不同时,无限循环就会开始,一切都会冻结.

If I set the same roles for both elements, for example ROLE_USER, everything works correctly. But when the roles are different for two elements, an infinite loop begins and everything freezes.

用于检查角色的组件:

@Component
export default class JhiNavbar extends Vue {
  @Inject('loginService')
  private loginService: () => LoginService;

  @Inject('accountService') private accountService: () => AccountService;
  public version = VERSION ? 'v' + VERSION : '';
  private currentLanguage = this.$store.getters.currentLanguage;
  private languages: any = this.$store.getters.languages;
  private hasAnyAuthorityValue = false;

  created() {}

  public get authenticated(): boolean {
    return this.$store.getters.authenticated;
  }

  public hasAnyAuthority(authorities: any): boolean {
    this.accountService()
      .hasAnyAuthorityAndCheckAuth(authorities)
      .then(value => {
        this.hasAnyAuthorityValue = value;
      });
    return this.hasAnyAuthorityValue;
  }
}

使用用户帐户的服务:

export default class AccountService {
  constructor(private store: Store<any>, private router: VueRouter) {
    this.init();
  }

  public init(): void {
    this.retrieveProfiles();
  }

  public retrieveProfiles(): void {
    axios.get('management/info').then(res => {
      if (res.data && res.data.activeProfiles) {
        this.store.commit('setRibbonOnProfiles', res.data['display-ribbon-on-profiles']);
        this.store.commit('setActiveProfiles', res.data['activeProfiles']);
      }
    });
  }

  public retrieveAccount(): Promise<boolean> {
    return new Promise(resolve => {
      axios
        .get('api/account')
        .then(response => {
          this.store.commit('authenticate');
          const account = response.data;
          if (account) {
            this.store.commit('authenticated', account);
            if (sessionStorage.getItem('requested-url')) {
              this.router.replace(sessionStorage.getItem('requested-url'));
              sessionStorage.removeItem('requested-url');
            }
          } else {
            this.store.commit('logout');
            this.router.push('/');
            sessionStorage.removeItem('requested-url');
          }
          resolve(true);
        })
        .catch(() => {
          this.store.commit('logout');
          resolve(false);
        });
    });
  }

  public hasAnyAuthorityAndCheckAuth(authorities: any): Promise<boolean> {
    if (typeof authorities === 'string') {
      authorities = [authorities];
    }

    if (!this.authenticated || !this.userAuthorities) {
      const token = localStorage.getItem('jhi-authenticationToken') || sessionStorage.getItem('jhi-authenticationToken');
      if (!this.store.getters.account && !this.store.getters.logon && token) {
        return this.retrieveAccount();
      } else {
        return new Promise(resolve => {
          resolve(false);
        });
      }
    }

    for (let i = 0; i < authorities.length; i++) {
      if (this.userAuthorities.includes(authorities[i])) {
        return new Promise(resolve => {
          resolve(true);
        });
      }
    }

    return new Promise(resolve => {
      resolve(false);
    });
  }

  public get authenticated(): boolean {
    return this.store.getters.authenticated;
  }

  public get userAuthorities(): any {
    return this.store.getters.account.authorities;
  }
}

@bigless提供解决方案:

There is solution by @bigless:

...
  private hasAdminAuthorityValue = false;
  private hasUserAuthorityValue = false;
...
  public hasAdminAuthority(): boolean {
    this.accountService()
      .hasAnyAuthorityAndCheckAuth('ROLE_ADMIN')
      .then(value => {
        this.hasAdminAuthorityValue = value;
      });
    return this.hasAdminAuthorityValue;
  }

  public hasUserAuthority(): boolean {
    this.accountService()
      .hasAnyAuthorityAndCheckAuth('ROLE_USER')
      .then(value => {
        this.hasUserAuthorityValue = value;
      });
    return this.hasUserAuthorityValue;
  }

推荐答案

这是由Vue的反应性引起的.您在 v-if 语句中使用了异步方法,这主要是一个坏主意.Vue监视此方法的所有响应依赖关系,如果任何依赖关系发生更改,它将再次重新评估该语句(这意味着再次调用该函数).那就是故事的一部分.

This is caused by Vue's reactivity. You use async method in v-if statement and it is mostly bad idea. Vue watches all reactive dependencies of this method and if any dependecy changes, it re-evaluates this statement again(which means calling that function again). Thats one part of the story.

现在为什么只在角色不同时才会发生这种情况.因为您使用共享属性 hasAnyAuthorityValue ,它是上述方法的反应性依赖项.

Now why this happens only when roles are different. Because you use shared property hasAnyAuthorityValue which is reactive dependency of the method mentioned above.

例如:它获得ROLE_USER的特权,立即返回 hasAnyAuthorityValue (同步),但稍后会在promise(async)中获取并更新此值.如果异步结果不变(一个角色),它可以工作,但是当 hasAnyAuthorityValue 的值在ROLE_USER和ROLE_ADMIN异步结果之间切换时,它陷入了无限循环.

For example: it gets privileges for ROLE_USER, returns hasAnyAuthorityValue immediately(sync), but later this value is fetched and updated in promise(async). It can work if async result doesn't change(one role), but when value of hasAnyAuthorityValue is toggling between ROLE_USER and ROLE_ADMIN async results, it is trapped in endless loop.

有很多解决方案.f.e.在创建阶段将两个 hasAnyAuthority(any)的结果保存为数据的属性值,或者为每个角色使用不同的属性名,而不是共享角色.

There are many solutions. f.e. save results of both hasAnyAuthority(any) as property value of data during create phase or use different property names for each role instead of shared one.

这篇关于检查角色时出现无限循环.VueJS的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆