Add the module source code


Associated with a Vue front-end application to achieve RBAC permission control a way, this article is relatively lazy, ha ha, or thank you for supporting friends.

Thanks to Li Yang’s invitation, I wrote this article. I don’t write much at ordinary times. Please forgive my mistakes.

Due to my work, I was looking for a management side template to develop the front-end interface skeleton of an e-banking system, so I found d2-admin, which seemed very appealing. Then I decided to make a demo with the separation of front and back ends to see whether the D2-admin template met the needs of our project. Then I think a permission management demo is very suitable for experiment, so I made jiiiiiin-Security permission system project. Here are some screenshots of the functions:

Why do we need a front end to implement RBAC

Before we say why we want to implement permissions control, we must understand the nature of what we want to implement, the following brief quote two introduction:

RBAC Role-based access control(English) :Role-based access control.RBAC), RBAC believes that authorization is actually a Who, What, How issue. In the RBAC model, who, What and how constitute the access triplet, that is, “who performs how operations on what (Which)”.

RBAC is an idea that can be implemented in any programming language, and its mature and simple control ideas are becoming more and more popular among developers.

More content, please you are not familiar with is bound to Google;

I think the front end is complementary to each other, so should be front access control, if we can learn some backend permissions distribution rule and the data structure is to be able to better cooperate with each other, of course, if completely ignore the background purview division, hard to do also can realize the two requirements above, just not on top of things, it is difficult to understand the meaning of doing this, Therefore, it is recommended that you take a look at the concept of RBAC, attribute the classical table structure, and attribute the business rules of background permissions when considering this problem.

“Rights management” usually we think of belong to the backend responsibility, but the two years with the rise of the SPA application, many applications are adopted to develop in the form of the separation of front and back side before but pure of front end development approach leads to a lot of hardware problem by back-end template language, now is bound to re-invent the wheel, At this time, I think the front-end is a security framework with the corresponding language of the back-end to be realized according to its own business needs. Here are our requirements:

  1. Improve the business module of our own Vue plug-in VUE-ViewPlus (this plug-in is written by us after one year of internal use to extract some common requirements for application development into modules, which is convenient for rapid application development)
  2. We believe that if we can intercept some unnecessary requests at the front end according to the permission rules configured at the back end, we can reduce unnecessary resource consumption at the back end and prompt normal users more quickly
  3. We need to address the need for administrative interface menus and buttons to be hidden based on back-end permissions
  4. We need to address the need for front-end view accessibility to be dynamically adjusted based on back-end permission configuration

These things are handled by post-class HTML template languages (such as JSPS in traditional Java) when the front and back ends are not separated, like this:

<html>
<sec:authorize access="hasRole('supervisor')">

This content will only be visible to users who have
the "supervisor" authority in their list of <tt>GrantedAuthority</tt>s.

</sec:authorize>
</html>
Copy the code

Docs. Spring. IO/spring – secu…

Achieve the goal

  • We want to determine whether the user can access the page according to the permission of the login user during the navigation
  • Implements the local UI component of the visible pageUsability or visibilityControl, that is, based on customizationv-accessCommand to compare the declared interface or resource to whether it is authorized
  • Before sending a request, the system checks the permission of the request interface. If the user does not have the permission to access the back-end interface, the system does not send the request but prompts the user in a friendly manner

implementation

To achieve the goal that we hope to judge whether users can access the page according to the permissions of login users when navigating the page, our solution is as follows:
  1. Gets the path list of accessible front-end pages for the logged-in user
  2. A public list of paths
  3. inrouternavigationalbeforeEachThe front hook determines whether the page requested by the current user is in one of the above two collections, if so, it releases, if not, it notifies the plug-in caller and lets it handle the failure itself

Here is the code implementation:

/** * RBAC permission control module */
import _ from 'lodash';
let _onPathCheckFail
let _publicPaths = []
let _authorizedPaths = []

* @type {Boolean} * @private */
let _superAdminStatus = false

const _compare = function(rule, path) {
  let temp = false
  if (_.isRegExp(rule)) {
    temp = rule.test(path)
  } else {
    temp = _.isEqual(path, rule)
  }
  return temp
}

/** * Check whether the login user has the permission to access the corresponding page * 1. Verify login * 2. Verify whether the page with access is in 'loginStateCheck#authorizedPaths' 'authorized' paths 'set * @param to * @param from * @param next * @private * /
const _rbacPathCheck = function(to, from, next) {
  if (_superAdminStatus) {
    next();
    return;
  }
  try {
    // By default, all resources require permission control
    let isAllow = false
    const path = to.path;
    // Check the public page collection first
    const publicPathsLength = _publicPaths.length
    for (let i = publicPathsLength; i--;) {
      const rule = _publicPaths[i];
      isAllow = _compare(rule, path)
      if (isAllow) {
        break; }}// Non-public page && already logged in
    if(! isAllow &&this.isLogin()) {
      // Check the collection of authorized pages
      const authorizedPathsLength = _authorizedPaths.length;
      for (let i = authorizedPathsLength; i--;) {
        const rule = _authorizedPaths[i];
        isAllow = _compare(rule, path);
        if (isAllow) {
          break; }}}if (isAllow) {
      next();
    } else {
      if (_.isFunction(_onPathCheckFail)) {
        if (_debug) {
          console.error('[v+] RBAC module detection: Users have no access [${path}], callback onPathCheckFail hook ');
        }
        this::_onPathCheckFail(to, from, next);
      } else {
        next(new Error('check_authorize_paths_fail')); }}}catch (e) {
    if (_debug) {
      console.error('[v+] RBAC module detection error:${e.message}`);
    }
    if (_.isFunction(_errorHandler)) {
      this::_errorHandler(e)
    }
  }
};

const rbacModel = {
  /** * [Optional] Some systems have a super user role, which can access any resources, pages, so if set, the login user will not do any permission verification, to save front-end resources * @param status */
  rabcUpdateSuperAdminStatus(status) {
    _superAdminStatus = status;
    this.cacheSaveToSessionStore('AUTHORIZED_SUPER_ADMIN_STATUS', _superAdminStatus)
  },
  /** * add the set of authorizedPaths * for example, after login, add the 'paths' that the user is authorized to access to 'LoginStateCheck#authorizedPaths' * @param paths */
  rabcAddAuthorizedPaths(paths) {
    this::rbacModel.rabcUpdateAuthorizedPaths(_.concat(_authorizedPaths, paths))
  },
  /** * Update the set of authorization paths * @param paths */
  rabcUpdateAuthorizedPaths(paths) {
    _authorizedPaths = [...new Set(paths)]
    this.cacheSaveToSessionStore('AUTHORIZED_PATHS', _authorizedPaths)
  },
  /** * Update public paths * @param paths */
  rabcUpdatePublicPaths(paths) {
    _publicPaths = [...new Set(paths)];
    this.cacheSaveToSessionStore('PUBLIC_PATHS', _publicPaths)
  },
  /** * Add public paths * @param paths */
  rabcAddPublicPaths(paths) {
    this::rbacModel.rabcUpdatePublicPaths(_.concat(_publicPaths, paths))
  },
  install(Vue, {
    /** * [*] System public route path set, that is, the page path that can be accessed by anyone * {Array} * 

* For example, the login page path, because we cannot determine whether users can access a page before login, so this configuration is required. Of course, if you need this configuration, you can also get it from the server side before initializing the plug-in, so that the front and back end will be more dynamic, but there is generally no need for this: ) * < p > * in the array item, can be a literal * * * * regular expressions, such as ` [/ ^ ((\ / Interbus) (?! \ / SubMenu) \ / +) $/] `, or it can be a string * < p > * matching rules: If you are in 'LoginStateCheck#publicPaths' ** system public path set **, then skip permission verification */

publicPaths = [], / [* * * *] the logged in user has access to the routing path path set * {Array < Object >} * < p > * in the Array item, can be a literal * * * * regular expressions, such as ` [/ ^ ((\ / Interbus) (?! \/SubMenu)\/.+)$/] ', which can also be a string *

* Matching rules: If in 'LoginStateCheck#authorizedPaths' ** requires authentication rule set **, then you need to check whether the user is logged in, and if not, deny access */

authorizedPaths = [], /** * [*] '$vp::onPathCheckFail(to, from, next)' *

*

onPathCheckFail = null, } = {}) { _onPathCheckFail = onPathCheckFail; router.beforeEach((to, from, next) = > { this::_rbacPathCheck(to, from, next); }); }};export default rbacModel; Copy the code

Here’s an explanation:

  1. The entire code ends up exporting a plain JSON object as a custom module of vue-ViewPlus, which will be mixin into its plug-in as a custom module:

    // The application entry mian
    import Vue from 'vue'
    import router from './router'
    import ViewPlus from 'vue-viewplus'
    import viewPlusOptions from '@/plugin/vue-viewplus'
    import rbacModule from '@/plugin/vue-viewplus/rbac.js'
    
    Vue.use(ViewPlus, viewPlusOptions)
    
    ViewPlus.mixin(Vue, rbacModule, {
      moduleName: 'Custom RBAC',
      router,
      publicPaths: ['/login'],
      onPathCheckFail(to, from, next) {
        NProgress.done()
        const title = to.meta.title
        this.dialog('You do not have access to [${_.isNil(title) ? to.path : title}】 page `)
          .then((a)= > {
            // The login page is displayed when there is no login
            // Carry the full path to the page to jump to after successful login
            next(false)})}})Copy the code

    If you don’t use or don’t want to use this plugin (vue-viewPlus is fine, just know that install for the exported object will be called in the application entry, passing in several install methods with the required parameters:

    • Route objects
    • List of common paths pages for the application
    • Handler function after permission verification failure

    This allows us to cache the applied public page Paths list in the initialization function, register the route hooks, and listen for route changes.

    I also use this plugin for a second purpose, which is to manage the user login state. Why do I use this state

  2. When listening for a public page access, the _rbacPathCheck function will:

    • First check whether the current user isSuper administrator, you can understand as the root user in Linux,If yes, the device permits the deviceOf course, if you want to achieve this effect, you need to view the user’s information according to the user information returned by the backend after loginrole, is the super administrator, if so, invoke file exportrabcUpdateSuperAdminStatusMethod, in this case, of the page instancethis.$vp.rabcUpdateSuperAdminStatusMethods (vue-viewplusBind each module’s exported API under the $vp attribute of the page instance (vm) :
    // Login page submit button binding method
    submit() {
          this.$refs.loginForm.validate(valid= > {
            if (valid) {
              / / login
              this.login({
                vm: this.username: this.formLogin.username,
                password: this.formLogin.password,
                imageCode: this.formLogin.code
              }).then((res) = > {
                // Change the user login status
                this.$vp.modifyLoginState(true);
                // Parse the login user data returned by the server to obtain the menu and permission related data
                const isSuperAdminStatus = parseUserRoleIsSuperAdminStatus(res.principal.admin.roles);
                this.$vp.toast('Login successful', {
                  type: 'success'
                });
                // If the redirect object does not exist, return to the top-level path
                this.$router.replace(this.$route.query.redirect || '/')})}else {
              // Login form verification failed
              this.$message.error('Form verification failed')}}}Copy the code
    • If not, check whether the path of the page to be accessed is in the public page Paths list _publicPaths** of the ** application. If yes, pass

      And do the judge is the premise of application login after successful needs to be authorized to the front of the paths set enclosing $vp. RabcUpdateAuthorizedPaths to plug-in:

      submit() {
            this.$refs.loginForm.validate(valid= > {
              if (valid) {
                / / login
                this.login({
                  vm: this.username: this.formLogin.username,
                  password: this.formLogin.password,
                  imageCode: this.formLogin.code
                }).then((res) = > {
                  this.$vp.rabcUpdateAuthorizedPaths(authorizeResources.paths); })}else {
                // Login form verification failed
                this.$message.error('Form verification failed')}}}Copy the code

      The data format is as follows:

      ["/mngauth/admin"."/index"."/mngauth"]
      Copy the code

      In addition, array values can be regular expressions;

    • If not, check whether the path of the page to be accessed is in the path set _authorizedPaths**, which the login user has access permission. If so, the check is allowed. If not, the whole verification is finished, determine that the user has no access to the page, call the _onPathCheckFail callback function. Notify the application, which prints a dialog to alert the user

    Since our goal is to abstract the entire business, we use callbacks to make the application actually sense and handle this situation;

    So we’ve accomplished our first goal;

To implement a local UI component that implements visible pagesUsability or visibilityControl, that is, based on customizationv-accessThe directive compares the declared interface or resource to whether it is authorized. Our solution is:
  1. To obtain a logged-in user:

    • List of resources owned by the authorized role, corresponding to the resource alias

      The data format is similar:

      ["MNG_USERMNG"."MNG_ROLEMNG"]
      Copy the code
    • A collection of back-end interfaces corresponding to a list of resources (or resources) owned by an authorized role

      The data format is similar:

      ["admin/dels/*"."admin/search/*/*/*"."admin/*/*/*"."role/list/*"."admin/*"]
      Copy the code

      But the default is RESTful:

      [{url: "admin/dels/*", method: "DELETE"}, ....]
      Copy the code

      Js regular expressions are also supported;

    With the above two (one of two) sets of authorization data, we can compare the conditional permissions declared by the user in the directive.

  2. Define a Vue directive, here named Access, which needs to have the following characteristics:

    • You can let the user declare different permission expressions, such as whether the button requires a set of interfaces or a resource alias
    • You can give the user control over whether to leave UI components undisplayed or unavailable after permission checks are not met

    Of course, to understand how the data structure back end is built above, you can refer to the table structure and permissions description

We continue to add logic to the code above, and here is the code implementation:

const rbacModel = {
  //....
  /** * update the set of authorized interfaces * @param interfaces */
  rabcUpdateAuthorizeInterfaces(interfaces) {
    _authorizeInterfaces = [...new Set(interfaces)]
    this.cacheSaveToSessionStore('AUTHORIZED_INTERFACES', _authorizeInterfaces)
  },
  /** * Add authorization interface set * @param interfaces */
  rabcAddAuthorizeInterfaces(interfaces) {
    this::rbacModel.rabcUpdateAuthorizeInterfaces(_.concat(_authorizeInterfaces, interfaces))
  },
  /** * Update the resource alias set * @param alias */
  rabcUpdateAuthorizeResourceAlias(alias) {
    _authorizeResourceAlias = [...new Set(alias)]
    this.cacheSaveToSessionStore('AUTHORIZED_RESOURCE_ALIAS', _authorizeResourceAlias)
  },
  /** * add a set of resource aliases * @param alias */
  rabcAddAuthorizeResourceAlias(alias) {
    this::rbacModel.rabcUpdateAuthorizeResourceAlias(_.concat(_authorizeResourceAlias, alias))
  },
  install(Vue, {
    //....
    / * * * (optional) the logged in user has access to resources alias set * {Array < Object >} * < p > * in the Array item, can be a literal * * * * regular expressions, such as ` [/ ^ ((\ / Interbus) (?! \/SubMenu)\/.+)$/] ', which can also be a string * 

* Matching rules: Because if both 'LoginStateCheck#authorizeInterfaces' are matched, there may be a case where n interfaces are required to access a resource, and we are configuring v-access="[n, n....] * When the interface set of our system is very large, it is bound to become a bottleneck, so we can declare an alias for the resource, the alias can represent the N interfaces, so it will be reduced from N + to N times matching; * /

authorizeResourceAlias = [], / [* * * *] the logged in user has access to the backend interface set * {Array < Object >} * < p > * 1. When a 'V-Access' directive is configured as a URL (default) validation format, this collection is used to match the list of authorized interfaces declared by the directive to be examined. If the match is successful, the directive is validated, otherwise the dom element is processed. * 2. *

* Array item, can be a ** regular expression literal **, such as' [/^((\/Interbus)(?! \/SubMenu)\/.+)$/] ', which can also be a string *

* Matching rules: Will be used to match the requested interface to the current collection before sending the Ajax request. If the match fails, the user does not have the request permission. * * If 'isRESTfulInterfaces' is set to' false ', the following format is used: * 'json * ["admin/dels/*",... ** If 'isRESTfulInterfaces' is set to' true ', ** note that this is the default **, the following format is used: ** json * [[{url: "admin/dels/*", method: "DELETE"}, ...]] * ``` */

authorizeInterfaces = [], /** * [*] specifies whether the collection of 'authorizeInterfaces' stores RESTful interfaces or regular interfaces. * [{url: 'admin/dels/*', method: 'DELETE'}] * If (true) the set of 'authorizeInterfaces' needs to store the structure: * [{url: 'admin/dels/*', method: 'DELETE'}] * If not (false), then the collection of 'authorizeInterfaces' needs to store the structure that is, regardless of the interface type: * ['admin/dels/*'] */ isRESTfulInterfaces = true{} = {})//.... this::_createRBACDirective(Vue) } }; export default rbacModel; Copy the code

First we add a few fields and the corresponding Settings interface to the plugin:

  • isRESTfulInterfaces
  • authorizeInterfaces
  • authorizeResourceAlias

In this way, we can maintain the user owned authorized resource alias list, resource (corresponding interface) back-end interface data list, and the default interface is considered RESTful data structure;

We can then define the directive (in the plug-in initialization method install) and, during the bind declaration cycle of the directive, parse the required permissions for the corresponding UI component declaration and compare them with the list of resources held. If the comparison fails, display or disable the UI component accordingly:


/** * Recommended: 'v-access:alias[. Disable]="'LOGIN'" 'v-access:[url][.disable]="'admin'"' v-access:[url][.disable]="'admin'" 'v-access:[url][.disable]="'admin'"' v-access:[url][.disable]=" ['LOGIN', 'WELCOME'] "* v - access: [url] [. Disable] =" [' admin ', 'admin / *'] "* for RESTful type interface: * v - access =" [{url: 'admin/search/*', method: 'POST'}]" * Uses url mode by default because it is more general * V-access ="['admin', 'admin/*']" * 

* where '[. Disbale]' is used to indicate that when checking that the user does not have permissions on the current declaration, Will add 'el.disabled = true' to the 'el' element of the current declaration directive, defaulting to hidden elements: 'el.style.display = 'none' *

* Example: ` ... '* The retrieval form above requires the login user to have access to the 'admin/search' interface to display * @param Vue * @private */

const _createRBACDirective = function(Vue) { Vue.directive('access', { bind: function(el, { value, arg, modifiers }) { if (_superAdminStatus) { return; } let isAllow = false const statementAuth = _parseAccessDirectiveValue2Arr(value) switch (arg) { case 'alias': isAllow = _checkPermission(statementAuth, _authorizeResourceAlias) break // Url mode is used by default case 'url': default: if (_isRESTfulInterfaces) { isAllow = _checkPermissionRESTful(statementAuth, _authorizeInterfaces) } else { isAllow = _checkPermission(statementAuth, _authorizeInterfaces) } } if(! isAllow) {if (_debug) { console.warn('[v+] RBAC access Failed: user has no access [${_.isObject(value) ? JSON.stringify(value) : value}】 `); } if (_.has(modifiers, 'disable')) { el.disabled = true; el.style.opacity = '0.5' } else { el.style.display = 'none'; }}}})}/** * Verify that the list required for the given directive display declaration is contained in the set of permissions that the authenticated user has. If yes, 'true' is returned to indicate that permission verification is passed * @param statementAuth * @Param authorizeCollection * @RETURNS {Boolean} * @private */ const _checkPermission = function(statementAuth, authorizeCollection) { let voter = [] statementAuth.forEach(url= > { voter.push(authorizeCollection.includes(url)) }) return! voter.includes(false)}/** * {@link _checkPermission} Adds the check for the interface type * @param statementAuth * @param authorizeCollection * @returns {Boolean} * @private */ const _checkPermissionRESTful = function(statementAuth, authorizeCollection) { let voter = [] const expectedSize = statementAuth.length const size = authorizeCollection.length for (let i = 0; i < size; i++) { const itf = authorizeCollection[i] if (_.find(statementAuth, itf)) { voter.push(true) // Remove the declared permission object judged successful statementAuth.splice(i, 1)}}// If the true content of the vote is the same as the length of the declaration permission, the check is passed return voter.length === expectedSize } const _parseAccessDirectiveValue2Arr = function(value) { let params = [] if (_.isString(value) || _.isPlainObject(value)) { params.push(value) } else if (_.isArray(value)) { params = value } else { throw new Error('Incorrect authorization identifier configured for Access, please check')}return params } Copy the code

Before using the directive, we also need to resolve the setting of the permission list required by the plug-in:

submit() {
      this.$refs.loginForm.validate(valid= > {
        if (valid) {
          / / login
          this.login({
            vm: this.username: this.formLogin.username,
            password: this.formLogin.password,
            imageCode: this.formLogin.code
          }).then((res) = > {
            // Change the user login status
            this.$vp.modifyLoginState(true);
            / /...
            const authorizeResources = parseAuthorizePaths(res.principal.admin.authorizeResources);
            this.$vp.rabcUpdateAuthorizeResourceAlias(authorizeResources.alias);
            const authorizeInterfaces = parseAuthorizeInterfaces(res.principal.admin.authorizeInterfaces);
            this.$vp.rabcUpdateAuthorizeInterfaces(authorizeInterfaces);
          	/ /...}})}Copy the code

Here parseAuthorizePaths and parseAuthorizeInterfaces returns to parse back-end login user resource and interface list, this is different from person to person, don’t stick;

This.$vp.modifyLoginState(true) is an interface provided by the vue-ViewPlus login identity control module, which can maintain the login state for the application, such as automatically setting the state to false when monitoring the back end return session timeout. See * here * for more, this is also a benefit of logic reuse;

Of course, if you just want to implement your own permission control module, and do not want to be so simple abstract, you can also hardcode into the project;

That completes our second goal;

Oh oh oh forgot to write down how we use this instruction, add:

<el-form v-access="{url: 'admin/search/*/*/*', method: 'POST'}" slot="search-inner-box" :inline="true" :model="searchForm" :rules="searchRules" ref="ruleSearchForm" class="demo-form-inline">/ /...</el-form>
Copy the code

{url: ‘admin/search/*/*/*’, method: ‘POST’;

For more declarations of other directives, see here

To achieve the goal of checking the permission of the request interface before sending the request, if the user does not have the permission to access the back-end interface, the request will not be sent, but the friendly prompt to the user, our solution is as follows:
  1. To obtain a logged-in user:

    • The collection of back-end interfaces corresponding to the list of resources (or resources) owned by the authorized role, which is completed when the second goal is achieved, after a successful login:this.$vp.rabcUpdateAuthorizeInterfaces(authorizeInterfaces);In this case, just reuse
  2. Intercepting requests. Here we’re using a vue-viewPlus util-http.js ajax module rewrapped against Axios. The nice thing about this is that 80% of my requests are handled automatically instead of having to write separate error handling code. Because the underlying use axios ajax plugins, corresponding the https://github.com/Jiiiiiin/jiiiiiin-security# provides the intercept request we hook table structure and permissions)

    With that in mind, we can probably write code

We continue to add logic to the code above, and here is the code implementation:

const rbacModel = {
  / /...
  install(Vue, {
    / /...
    /** * [*] '$vp::onPathCheckFail(to, from, next)' * 

*/

onAjaxReqCheckFail = null } = {}) { _onAjaxReqCheckFail = onAjaxReqCheckFail; this::_rbacAjaxCheck() } }; Copy the code

Once again in the plug-in object, the onAjaxReqCheckFail for the desired configuration is declared first, followed by the axiOS interception declaration by calling _rbacAjaxCheck:


/** * is used to match the interface of the request and the current collection before sending ajax requests. If the match fails, the user does not have the request permission. Therefore, the user does not send background requests directly to reduce the unnecessary waste of resources on the backend * @private */
const _rbacAjaxCheck = function() {
  this.getAjaxInstance().interceptors.request.use(
    (config) = > {
      const { url, method } = config
      const statementAuth = []
      let isAllow
      if (_isRESTfulInterfaces) {
        const _method = _.toUpper(method)
        statementAuth.push({ url, method: _method });
        isAllow = _checkPermissionRESTful(statementAuth, _authorizeInterfaces)
        / / TODO because the request of the intercepted ` {url: "admin / 0/1/10", method: "GET"} ` found no similar in Java org. Springframework. Util. AntPathMatcher;
        {url: "admin/*/*/*", method: "GET"} ', temp = antPathMatcher.match(aninterface.geturl (), reqURI) '
        // so this requirement cannot be implemented for the time being :)
        console.log('statementAuth', isAllow, statementAuth, _authorizeInterfaces)
      } else {
        isAllow = _checkPermission(statementAuth, _authorizeInterfaces)
      }
      if (isAllow) {
        return config;
      } else {
        if (_debug) {
          console.warn('[v+] RBAC Ajax permission detection failed: user has no right to send request [${method}-${url}】 `);
        }
        if (_.isFunction(_onAjaxReqCheckFail)) {
          this::_onAjaxReqCheckFail(config);
        } else {
          throw new Error('check_authorize_ajax_req_fail');
        }
      }
    },
    error => {
      return Promise.reject(error)
    }
  )
}
Copy the code

This. GetAjaxInstance () is called _rbacAjaxCheck. We specify this, this::_rbacAjaxCheck(), and this is the $vp object. The $VP property that vue-viewPlus binds to the vue instance;

If the check succeeds, axios returns the required config. If the check fails, the configured _onAjaxReqCheckFail notification is called. If the application fails to handle permissions, a toast will pop up indicating that the user has insufficient permissions.

It looks like we’ve accomplished all our goals, hahaha.

Writing articles is much more tiring than typing code.

Unfortunately, we didn’t achieve the third goal. The problem is that, as described in TODO in the code snippet above, I didn’t solve the permission comparison for RESTful PathValue type interfaces. The library I used at the back end was through:

 log.debug("Inner tube permission check begins: {} {} {}", admin.getUsername(), reqURI, reqMethod);
                for (Role role : roles) {
                    boolean temp;
                    for (Resource resource : role.getResources()) {
                        for (Interface anInterface : resource.getInterfaces()) {
                            temp = antPathMatcher.match(anInterface.getUrl(), reqURI) && reqMethod.equalsIgnoreCase(anInterface.getMethod());
                            if (temp) {
                                hasPermission = true;
                                break; }}}}Copy the code

Org. Springframework. Util. AntPathMatcher provides methods to complete, but I didn’t find the right libraries to js contrast:

{url: "admin/*/*/*".method: "GET"} < > {url: "admin/0/1/10".method: "GET"}
Copy the code

Such two objects, so have patience to see friends here, if you solve this problem, please contact me, thank you.

Thank you for reading this patiently. If you think it is helpful, please help to support my two projects:

vue-viewplus

jiiiiiin-security

Move your little hands, ask for star, ah, ha ha ha.