微服务系统:vue+elementui +springcloud——登录auth功能认证授权(JWT、SSO)+人员角色菜单功能+架构拦截aop功能实现

效果:

前台空架子:
在这里插入图片描述
后台管理系统
在这里插入图片描述

在这里插入图片描述
架构图:

在这里插入图片描述

单点登录算法步奏:

1.全路由设置(import页面、基础路由、模块路由)准备,路由就是把所有页面模块的路径都按照权限管理起来.要和后台路由对应起来

import Vue from 'vue'
import Router from 'vue-router' //导入Router 路由跳转
 slow.so only in production use Lazy Loading
/* layout */
import Layout from '../views/layout/Layout'  //导入主页面布局
import inj_pro from "../views/production_opt/inj_pro";         //导入模块页面
import well_loc from "../views/production_opt/well_loc";
import method from "../views/production_opt/method";
import formation from "../views/production_opt/formation";
import all from "../views/production_opt/all";
import cat from "../views/model/cat";
import upload from "../views/model/upload";
const _import = require('./_import_' + process.env.NODE_ENV)
Vue.use(Router)

  //持久通用的路由
export const constantRouterMap = [           
  {path: '/login', component: _import('login/index'), hidden: true},           //登陆页面
  {path: '/404', component: _import('404'), hidden: true},                      //错误页面
  
   //主页面的映射方式/
  {
    path: '/',                             //路径
    component: Layout,            //主页面
    redirect: '/dashboard',          //main重定向到dashboard页面,真正的页面
    name: '首页',
    hidden: true,
    children: [{
      path: 'dashboard', component: _import('dashboard/index')
    }]
  }
]
export default new Router({
  mode: 'history', //后端支持可开
  scrollBehavior: () => ({y: 0}),
  routes: constantRouterMap
})
  //动态路由
export const asyncRouterMap = [        
  {
    path: '/model',                 //映射
    component: Layout,          //组件是主页
    redirect: upload,             //模块页面
    name: '模型管理',
    meta: {title: '模型管理', icon: 'tree'},  //图标
    children: [
      {
        path: 'upload',         映射
        name: '上传模型',
        component: upload,                     //组件是上传页
        meta: {title: '上传模型', icon: 'example'},  
        menu: 'upload'
      },
      {
        path: 'cluster',
        name: '查看模型',
        component: cat,
        meta: {title: '查看模型', icon: 'example'},
        menu: 'cat'
      }
    ]
  },
  {
    path: '/production',
    component: Layout,
    redirect: inj_pro,
    name: '生产优化',
    meta: {title: '生产优化', icon: 'table'},
    children: [
      {
        path: 'injec_pro',
        name: '注采优化',
        component: inj_pro,
        meta: {title: '注采优化', icon: 'user'},
        menu: 'injec_pro'
      },
      {
        path: 'well_loc',
        name: '井位优化',
        component: well_loc,
        meta: {title: '井位优化', icon: 'user'},
        menu: 'well_loc'
      },
      {
        path: 'method',
        name: '措施优化',
        component: method,
        meta: {title: '措施优化', icon: 'user'},
        menu: 'method'
      },
      {
        path: 'formation',
        name: '层位优化',
        component: formation,
        meta: {title: '层位优化', icon: 'user'},
        menu: 'formation'
      },
      {
        path: 'all',
        name: '整体优化',
        component: all,
        meta: {title: '整体优化', icon: 'password'},
        menu: 'all'
      },
    ]
  },
  {path: '*', redirect: '/404', hidden: true}
]

2.后台请求拦截器、数据库配置等等配置

web拦截器:控制请求类型,启动就一直在监控

Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        //允许全部请求跨域
        registry.addMapping("/**")          //**代表全部
                //.allowedOrigins("http://localhost:8080")
//                .allowedOrigins("http://localhost:8088")
                .allowedMethods("GET", "POST","OPTIONS")
                .allowCredentials(true).maxAge(3600);

    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");

        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new SsoInterceptor())
                .excludePathPatterns("/shiro/updatePermission")
                .excludePathPatterns("/login/auth")
                .addPathPatterns("/**");

        //验证有问题,待解决
//        registry.addInterceptor(new LoginInterceptor())
//                .excludePathPatterns("/error")
//                .excludePathPatterns("/login/**")
//                .addPathPatterns("/**");
    }
}

单点登录拦截器:HandlerInterceptorAdapter拦截器配置,只在刷新和登录时拦截

日志记录,可以记录请求信息的日志,以便进行信息监控、信息统计等。
权限检查:如登陆检测,进入处理器检测是否登陆,如果没有直接返回到登陆页面。
性能监控:典型的是慢日志。
在HandlerInterceptorAdapter中主要提供了以下的方法:
preHandle:在方法被调用前执行。在该方法中可以做类似校验的功能。如果返回true,则继续调用下一个拦截器。如果返回false,则中断执行,也就是说我们想调用的方法 不会被执行,但是你可以修改response为你想要的响应。
postHandle:在方法执行后调用。
afterCompletion:在整个请求处理完毕后进行回调,也就是说视图渲染完毕或者调用方已经拿到响应
package com.teradata.zuul.interceptor;

import com.google.gson.Gson;
import com.teradata.common.bean.ErrorEnum;
import com.teradata.common.util.JWTUtil;
import com.teradata.zuul.service.RedisService;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

/**
 

 * 单点登录拦截器
 */
public class SsoInterceptor extends HandlerInterceptorAdapter {

    @Override 
    public boolean preHandle(HttpServletRequest servletRequest, HttpServletResponse servletResponse, Object handler) throws Exception {        //HttpServletRequest 请求和响应
//获取请求头中的Authorization属性
        String authorization = servletRequest.getHeader("Authorization");
//BeanFactory 中获取redis,redis已经配置好了
        BeanFactory factory = WebApplicationContextUtils.getRequiredWebApplicationContext(servletRequest.getServletContext());
        RedisService redisService = (RedisService) factory.getBean("redisService");
        boolean flag= false;

        if (authorization != null && JWTUtil.verifyToken(authorization)){
            //校验登陆的token是否与缓存中的token保持一致
            String userId = JWTUtil.getUsername(authorization);           //根据auth解析出userid
            if (((String)redisService.get(userId)).equalsIgnoreCase(authorization)){     //从redis里面获取userid看是否和传入的相等
            //如果成功返回true
                flag = true;
                return flag;
            }
        }
//否则返回false和servletResponse(内容是没有登陆)
        servletResponse.setCharacterEncoding("UTF-8");
        //Subject subject = getSubject(request, response);
        PrintWriter printWriter = servletResponse.getWriter();
        servletResponse.setContentType("application/json;charset=UTF-8");
        servletResponse.setHeader("Access-Control-Allow-Origin", servletRequest.getHeader("Origin"));
        servletResponse.setHeader("Access-Control-Allow-Credentials", "true");
        servletResponse.setHeader("Vary", "Origin");
        String respStr;
        respStr = "you have not right to access";//返回的内容
        printWriter.write(new Gson().toJson(new com.teradata.common.bean.ResponseBean(ErrorEnum.ERROR_10002.getErrorCode(),ErrorEnum.ERROR_10002.getErrorMsg(),"")));
        printWriter.flush();
        servletResponse.setHeader("content-Length", respStr.getBytes().length + "");//设置响应头
        return flag;
    }


}


yuml配置数据库文件

datasource:
  master:
    url: jdbc:mysql://localhost:3306/aa?useUnicode=yes&characterEncoding=UTF-8&useSSL=false
    driverClassName: com.mysql.jdbc.Driver
    username: root
    password: root


配置数据库代码

package com.teradata.zuul.config;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;

/**
 * @author xuyaohui
 * @date 2018/7/27 0027 上午 10:32
 */
@Configuration
@MapperScan(basePackages = "com.teradata.zuul.repository",sqlSessionFactoryRef = "masterSqlSessionFactory")
public class DataSourceConfig {  //类名 数据库配置

    @Bean(name = "masterDataSource")      //数据源的创建
    @ConfigurationProperties("datasource.master")      //找到yuml文件的字段自动注入参数
    public DataSource masterDataSource(){
        return DataSourceBuilder.create().build();//调用DataSourceBuilder来创建
    }

    @Bean(name = "masterSqlSessionFactory")//注入masterSqlSessionFactory工厂
    public SqlSessionFactory sqlSessionFactory(@Qualifier("masterDataSource") DataSource dataSource) throws Exception {//调用masterDataSource创建数据源
        SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);//添加数据源
        sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath*:mapper/*.xml"));//设置map.xml的位置
        return sessionFactoryBean.getObject(); //返回工厂
    }
}

``
3.点击登录:先去校验auth。。。
.登录的服务层同时获取(User.login/auth方法)、用户对象和权限菜单的数据、设置token到cookie

控件
 <el-input type="password" @keyup.enter.native="handleLogin" v-model="loginForm.password"
                  autoComplete="on"></el-input>
JS

export default {
    name: 'login',
    data() {
      return {
        loginForm: { //参数
          username: 'admin',
          password: '123456'
        },
        loginRules: {
          username: [{required: true, trigger: 'blur', message: "请输入用户名"}],
          password: [{required: true, trigger: 'blur', message: "请输入密码"}]
        },
        loading: false
      }
    },
    methods: {
      handleLogin() {
        this.$refs.loginForm.validate(valid => {
          if (valid) {
            this.loading = true
            //请求auth,loginForm参数
            this.$store.dispatch('Login', this.loginForm).then(data => {              //跳转autn后台的 js
              console.log('获取到的data: '+data.msg);
              this.loading = false
              if ("success" === data.msg) {
                //成功直接跳转主页面layout
                this.$router.push({path: '/'})
              } else {
                this.$message.error("账号/密码错误");
              }
            }).catch(() => {
              this.loading = false
            })
          } else {
            this.$message.error("请输入所有字段");
            return false
          }
        })
      }
    }
  }
</script>

user.js里的方法

actions: {
    // 登录
    Login({commit, state}, loginForm) {
      return new Promise((resolve, reject) => {
        api({
          url: "login/auth",   //后台
          method: "post",
          data: loginForm
        }).then(data => {
          if (data.msg === "success") {  //成功后
            //使用sessionStorage存储token值
           
            //前台存在session的属性cloud-ida-token中,存在服务器中
            sessionStorage.setItem('cloud-ida-token',data.data);
          
            //cookie中保存前端登录状态,设置了已经登录字段
            setToken();
          }
          resolve(data);
        }).catch(err => {
          reject(err)
        })
      })
    },
    
export function setToken() {
  return Cookies.set(LoginKey, "1")
}

后台auth

 
         
    @PostMapping("/login/auth")
    public ResponseBean login(@RequestBody JSONObject jsonObject){
        String username = jsonObject.getString("username");
        String password = jsonObject.getString("password");//传参

        try {
            User user=userService.getUserByAccount(username);//用id查到user

            if (user.getPassword().equalsIgnoreCase(password)){//对比密码是否正确
                Date date = new Date(System.currentTimeMillis()+EXPIRE_TIME);
                Algorithm algorithm = Algorithm.HMAC256(SECRET);
                String token= JWT.create()              //产生token 
                        .withClaim("username", username)
                        .withClaim("roles",user.getRoles())
                        .withExpiresAt(date)
                        .sign(algorithm);
                redisService.remove(username);                 
                //redisService去掉以前的token,新创建token
                System.out.println("before: "+token);
                redisService.set(username,token);
                System.out.println("after: "+ redisService.get(username));

                // 附带username信息
                return new ResponseBean(200,"success",token);//返回数据的第三个是数据
            }
            return new ResponseBean(200,"false","用户名或密码错误");

        } catch (UnsupportedEncodingException e) {
            return new ResponseBean(200,"false","异常抛出");
        }
    }

//根据userid(admin名字)查user
package com.teradata.zuul.service;
import com.teradata.zuul.bean.PermissionRole;
import com.teradata.zuul.bean.User;
import com.teradata.zuul.bean.UserPermission;
import com.teradata.zuul.repository.UserDao;
import org.hibernate.validator.constraints.CreditCardNumber;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Set;
 

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public User getUserByAccount(String userAccount){

        User user=userDao.getUserByName(userAccount);
        if (user!=null){
           Set<String> permissions = userDao.getUserPermissions(userAccount);
            user.setPermission(permissions);

            //获取菜单
            Set<String> s=userDao.getMenuListByName(userAccount);
            user.setMenuList(userDao.getMenuListByName(userAccount));
        }

        return user;
    }

User bean实体属性

public class User implements Serializable{

    //用户标识
    private String userAccount;

    private String password;

    //用户角色(多角色)
    private String roles;

    private Set<String> permission;

    /**
     * 该用户所有菜单
     */
    private Set<String> menuList;

获取到了user拥有的的菜单栏目和操作权限
在这里插入图片描述

获取到user的权限
4.登陆成功后getinfo:跳转路由页面 layout主页下的dashboat。
会被前台拦截器拦截,已经登录但是没有信息:获取信息getinfo.

登陆成功跳转

handleLogin() {
        this.$refs.loginForm.validate(valid => {
          if (valid) {
            this.loading = true
            //请求
            this.$store.dispatch('Login', this.loginForm).then(data => {
              console.log('获取到的data: '+data.msg);
              this.loading = false
              if ("success" === data.msg) {
                //成功直接跳转主页面layout
                this.$router.push({path: '/'})
              } else {
                this.$message.error("账号/密码错误");
              }
            }).catch(() => {
              this.loading = false
            })
          } else {
            this.$message.error("请输入所有字段");
            return false
          }
        })

前台拦截器:::跳转页面前被拦截下来,是src下面的permission.js,

import router from './router'
import store from './store'
import NProgress from 'nprogress' // Progress 进度条
import 'nprogress/nprogress.css' // Progress 进度条样式
import {getToken} from '@/utils/auth' // 验权
const whiteList = ['/login', '/404'] //白名单直接跳转


//每次使用路由都会判断
router.beforeEach((to, from, next) => {
  NProgress.start()


  //从cookie中取出token,,,getToken()
 
  if (getToken()) {
    //如果是重新登录的情况
    if (to.path === '/login') {
      next({path: '/'})
      NProgress.done() // 结束Progress
      
      //如果store.getters.role为null,则GetInfo
    } else if (!store.getters.role) {
      //如果是没获取state信息的情况,跳转后台GetInfo
      store.dispatch('GetInfo').then(() => {
        next({...to})
      })
    } else {
    //其他情况:也就是信息都有了的情况,直接跳转
      next()
    }
  } else if (whiteList.indexOf(to.path) !== -1) {
    //如果前往的路径是白名单内的,就可以直接前往
    next()
  } else {
  
    //如果路径不是白名单内的,而且又没有登录,就跳转登录页面
    next('/login')
    NProgress.done() // 结束Progress
  }
})
router.afterEach(() => {
//跳转之后,进度条关闭
  NProgress.done() // 结束Progress
})

从user类里的GetInfo方法
前端debug

GetInfo({commit, state}) {
      return new Promise((resolve, reject) => {

        api({
          url: '/login/getInfo',
          method: 'get'
        }).then(data => {
          //设置用户
          commit('SET_USER', data.data);
          //cookie保存登录状态,仅靠vuex保存的话,页面刷新就会丢失登录状态
          setToken();
          //生成路由
          let userPermission = data.data ;
          console.log("userPermission"+userPermission);
          store.dispatch('GenerateRoutes', userPermission).then(() => {
            //生成该用户的新路由json操作完毕之后,调用vue-router的动态新增路由方法,将新路由添加
            router.addRoutes(store.getters.addRouters)
          })
          resolve(data)
        }).catch(error => {
          reject(error)
        })
      })
    },

前台拦截器api.js:每次请求axios 的时候设置请求头——加auth(token)
vue+vue-resource设置请求头(带上token)
在这里插入图片描述
知乎http请求原理

import axios from 'axios'
import {Message, MessageBox} from 'element-ui'
import {getToken} from '@/utils/auth'
import store from '../store'

// 创建axios实例service 
const service = axios.create({
  baseURL: process.env.BASE_URL, // api的base_url
  timeout: 15000                  // 请求超时时间2
})

// service 对象调用了request拦截器
service.interceptors.request.use(config => {
//从sessionStorage获取token给赋值到headers
  config.headers.Authorization=sessionStorage.getItem('cloud-ida-token');
  return config
}, error => {
  // Do something with request error
  console.error(error) // for debug
  Promise.reject(error)
})

// service 对象调用了 respone拦截器
service.interceptors.response.use(
  response => {
    const res = response.data;
    if (res.code == "200") {
    //如果返回200
      return res
    }
    //如果返回10002
    if (res.code == '10002') {
      Message({
      //弹出错误消息
        showClose: true,
        //使用返回的错误信息
        message: res.msg,
        type: 'error',
        duration: 3 * 1000,
        onClose: () => {
          store.dispatch('FedLogOut').then(() => {
            location.reload()// 为了重新实例化vue-router对象 避免bug
          })
        }
      });
      return Promise.reject(res.msg)
    }else{
    //如果返回其他错误
      Message({
        message: res.msg,
        type: 'error',
        duration: 3 * 1000
      })
      return res
    }
  },
  error => {
    console.error('err' + error)// for debug
    Message({
      message: error.message,
      type: 'error',
      duration: 3 * 1000
    })
    return Promise.reject(error)
  }
)
export default service

getInfo后台:获取token对比,成功才给userinfo信息。
JWTUtil代替了权限认证接口,到时候请求接口获取user,再去getuserinfo就行。

服务器没法通过session来验证你的身份,所以服务器的过滤器(或拦截器)会过滤掉你的请求,让你返回登陆界面重新登录,使用户体验变差。
Authorization里面放的就是token,就相当于每次发送请求的时候,拦截器都会拦截一次你的请求,
把你请求头部的Authorization拿出来,与当前存在服务器上的token做对比。

     * @return
     */
    @GetMapping("/login/getInfo")
    public ResponseBean getInfo(ServletRequest req, ServletResponse resp) {
//获取参数Authorization
        HttpServletRequest httpServletRequest = (HttpServletRequest) req;
        String authorization = httpServletRequest.getHeader("Authorization");
        //token获取id来获取用户信息
        System.out.println("获取的auth: "+authorization);
        //再次获取user类 ,getUserByAccount
        if (authorization!=null){
            String userId=JWTUtil.getUsername(authorization);
            
            return new ResponseBean(200,"success",userService.getUserByAccount(userId));
        }
        return new ResponseBean(401,"false","获取用户信息出错");
    }

成功返回到js

GetInfo({commit, state}) {
      return new Promise((resolve, reject) => {

        api({
          url: '/login/getInfo',
          method: 'get'
        }).then(data => {


          //设置用户user
          commit('SET_USER', data.data);
          //cookie保存登录状态,仅靠vuex保存的话,页面刷新就会丢失登录状态
          setToken();

          //生成路由
          let userPermission = data.data ;
          console.log("userPermission"+userPermission);
          store.dispatch('GenerateRoutes', userPermission).then(() => {
            //生成该用户的新路由json操作完毕之后,调用vue-router的动态新增路由方法,将新路由添加
            router.addRoutes(store.getters.addRouters)
          })
          resolve(data)
        }).catch(error => {
          reject(error)
        })
      })
    },

返回后赋值给user对象:
前台的user.js,接收user:就相当于一个类, state、mutations是构造方法,actions是方法

import {getInfo, login, logout} from '@/api/login'
import {getToken, removeToken, setToken} from '@/utils/auth'
import {default as api} from '../../utils/api'
import store from '../../store'
import router from '../../router'

const user = {
  state: {
    nickname: "",
    userId: "",
    avatar: 'https://www.gravatar.com/avatar',
    role: '',
    menus: [],
    permissions: [],
  },
  mutations: {
    SET_USER: (state, userInfo) => {
      state.nickname = userInfo.userAccount;
      state.userId = userInfo.userAccount;
      state.role = userInfo.roles;
      state.menus = userInfo.menuList;
      state.permissions = userInfo.permission;
    },
    RESET_USER: (state) => {
      state.nickname = "";
      state.userId = "";
      state.role = '';
      state.menus = [];
      state.permissions = [];
    }
  },
  actions: {
    // 登录
    Login({commit, state}, loginForm) {
    getinfo(){。。。。。。}

前台的store相当于类工厂

import Vue from 'vue'
import Vuex from 'vuex'
import app from './modules/app'
import user from './modules/user'
import permission from './modules/permission'
import getters from './getters'

Vue.use(Vuex)

const store = new Vuex.Store({
  modules: {
    app,                //app.js类
    user,    //user.js类
    permission   //permission .js类
  },
  getters
})

export default store

返回后生成路由
permission是权限类,里面有创建路由的方法,判断是否有权限,过滤路由:

import {asyncRouterMap, constantRouterMap} from '@/router/index'

/**
 * 判断用户是否拥有此菜单
 * @param menus
 * @param route
 */
function hasPermission(menus, route) {
  if (route.menu) {
    /*
    * 如果这个路由有menu属性,就需要判断用户是否拥有此menu权限
    */
    return menus.indexOf(route.menu) > -1;
  } else {
    return true
  }
}

/**
 * 递归过滤异步路由表,返回符合用户菜单权限的路由表
 * @param asyncRouterMap
 * @param menus
 */
function filterAsyncRouter(asyncRouterMap, menus) {
  const accessedRouters = asyncRouterMap.filter(route => {
    //filter,js语法里数组的过滤筛选方法
    if (hasPermission(menus, route)) {
      if (route.children && route.children.length) {
        //如果这个路由下面还有下一级的话,就递归调用
        route.children = filterAsyncRouter(route.children, menus)
        //如果过滤一圈后,没有子元素了,这个父级菜单就也不显示了
        return (route.children && route.children.length)
      }
      return true
    }
    return false
  })
  return accessedRouters
}
//permission 类
const permission = {
  state: {
    routers: constantRouterMap, //本用户所有的路由,包括了固定的路由和下面的addRouters
    addRouters: [] //本用户的角色赋予的新增的动态路由
  },
  mutations: {
    SET_ROUTERS: (state, routers) => {
    //设置路由的方法
      state.addRouters = routers
      state.routers = constantRouterMap.concat(routers) //将固定路由和新增路由进行合并, 成为本用户最终的全部路由信息
console.log(state.routers);
    }
  },
  actions: {
    GenerateRoutes({commit}, userPermission) {
      //生成路由
      return new Promise(resolve => {
      
        const role = userPermission.roles;//角色
        const menus = userPermission.menuList;//菜单
        //声明 该角色可用的路由
        let accessedRouters
        if (role === '管理员') {
          //如果角色里包含'管理员',那么所有的路由都可以用
          //其实管理员也拥有全部菜单,这里主要是利用角色判断,节省加载时间
          accessedRouters = asyncRouterMap
        } else {
          //否则需要通过以下方法来筛选出本角色可用的路由
          console.log("过滤前"+menus)
          accessedRouters = filterAsyncRouter(asyncRouterMap, menus)
          console.log("过滤后"+accessedRouters)
        }
        //调用执行设置路由的方法
        commit('SET_ROUTERS', accessedRouters)
        resolve()
      })
    }
  }
}
export default permission

                 7.服务层方法调用mapper映射sql语句 到dao层、 	
                 8.Token、用户信息和用户权限菜单 写入本地sessionStorage缓存和user用户对象(commit('SET_USER', data.data)方法;) (vuexx,store仓库)
                 9.全路由对比登录后得到的路由许可,得到用户的菜单路由并暴露(js)、
                  10登录成功直接跳转主页面layout、 
                  11侧边栏去找路由store定义(用户的菜单)、
                   12点击侧边栏跳转路由占位符main那里;
          12也可以是跳到home页面再请求菜单数据再对比再渲染。

遇到的Bug:请求不到新加的权限菜单,是因为获取菜单那里写死了,父id必须15。Debug找问题源头

在这里插入图片描述
/

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值