后台:
前端:
项目:
前端选用的lin-xin大神的前端模板(github地址)。该方案作为一套多功能的后台框架模板,适用于绝大部分的后台管理系统(Web Management System)开发。基于 vue.js,使用 vue-cli3 脚手架,引用 Element UI 组件库,方便开发快速简洁好看的组件。分离颜色样式,支持手动切换主题色,而且很方便使用自定义主题色。
<template>
<div class="login-wrap">
<div class="ms-login">
<div class="ms-title">后台管理系统div>
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="0px" class="ms-content">
<el-form-item prop="userId">
<el-input v-model="ruleForm.userId" placeholder="userId">
<el-button slot="prepend" icon="el-icon-lx-people">el-button>
el-input>
el-form-item>
<el-form-item prop="password">
<el-input type="password" placeholder="password" v-model="ruleForm.password" @keyup.enter.native="submitForm('ruleForm')">
<el-button slot="prepend" icon="el-icon-lx-lock">el-button>
el-input>
el-form-item>
<div class="login-btn">
<el-button type="primary" @click="submitForm('ruleForm')">登录el-button>
div>
<p class="login-tips">Tips : 用户名和密码随便填。p>
el-form>
div>
div>
template>
<script>
export default {
data: function(){
return {
ruleForm: {
userId: 'admin',
password: '1234'
},
rules: {
userId: [
{ required: true, message: '请输入用户名', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' }
]
}
}
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.$axios.post('/sys/login', this.ruleForm ).then((res) => {
if(res.data.success){
localStorage.setItem('ms_userId',this.ruleForm.userId);
this.$router.push('/dashboard');
} else {
this.$message.error(res.data.msg);
}
})
} else {
console.log('error submit!!');
return false;
}
});
}
}
}
script>
<style scoped>
.login-wrap{
position: relative;
width:100%;
height:100%;
background-image: url(../../assets/img/login-bg.jpg);
background-size: 100%;
}
.ms-title{
width:100%;
line-height: 50px;
text-align: center;
font-size:20px;
color: #fff;
border-bottom: 1px solid #ddd;
}
.ms-login{
position: absolute;
left:50%;
top:50%;
width:350px;
margin:-190px 0 0 -175px;
border-radius: 5px;
background: rgba(255,255,255, 0.3);
overflow: hidden;
}
.ms-content{
padding: 30px 30px;
}
.login-btn{
text-align: center;
}
.login-btn button{
width:100%;
height:36px;
margin-bottom: 10px;
}
.login-tips{
font-size:12px;
line-height:30px;
color:#fff;
}
style>
import Vue from 'vue';
import Router from 'vue-router';
Vue.use(Router);
export default new Router({
mode: 'hash',
base: __dirname,
routes: [
{
path: '/',
redirect: '/login'
},
{
path: '/',
component: resolve => require(['../components/common/Home.vue'], resolve),
meta: { title: '自述文件' },
children:[
{
path: '/dashboard',
component: resolve => require(['../components/page/Dashboard.vue'], resolve),
meta: { title: '系统首页' }
},
{
path: '/icon',
component: resolve => require(['../components/page/Icon.vue'], resolve),
meta: { title: '自定义图标' }
},
{
path: '/table',
component: resolve => require(['../components/page/BaseTable.vue'], resolve),
meta: { title: '基础表格' }
},
{
path: '/user',
component: resolve => require(['../components/page/User.vue'], resolve),
meta: { title: '用户管理' }
},
{
path: '/tabs',
component: resolve => require(['../components/page/Tabs.vue'], resolve),
meta: { title: 'tab选项卡' }
},
{
path: '/form',
component: resolve => require(['../components/page/BaseForm.vue'], resolve),
meta: { title: '基本表单' }
},
{
// 富文本编辑器组件
path: '/editor',
component: resolve => require(['../components/page/VueEditor.vue'], resolve),
meta: { title: '富文本编辑器' }
},
{
// markdown组件
path: '/markdown',
component: resolve => require(['../components/page/Markdown.vue'], resolve),
meta: { title: 'markdown编辑器' }
},
{
// 图片上传组件
path: '/upload',
component: resolve => require(['../components/page/Upload.vue'], resolve),
meta: { title: '文件上传' }
},
{
// vue-schart组件
path: '/charts',
component: resolve => require(['../components/page/BaseCharts.vue'], resolve),
meta: { title: 'schart图表' }
},
{
// 拖拽列表组件
path: '/drag',
component: resolve => require(['../components/page/DragList.vue'], resolve),
meta: { title: '拖拽列表' }
},
{
// 拖拽Dialog组件
path: '/dialog',
component: resolve => require(['../components/page/DragDialog.vue'], resolve),
meta: { title: '拖拽弹框' }
},
{
// 国际化组件
path: '/i18n',
component: resolve => require(['../components/page/I18n.vue'], resolve),
meta: { title: '国际化' }
},
{
// 权限页面
path: '/permission',
component: resolve => require(['../components/page/Permission.vue'], resolve),
meta: { title: '权限测试', permission: true }
},
{
path: '/404',
component: resolve => require(['../components/page/404.vue'], resolve),
meta: { title: '404' }
},
{
path: '/403',
component: resolve => require(['../components/page/403.vue'], resolve),
meta: { title: '403' }
}
]
},
{
path: '/login',
component: resolve => require(['../components/page/Login.vue'], resolve)
},
{
path: '*',
redirect: '/404'
}
]
})
axios.interceptors.response.use(res => {
if(!res.data.success && res.data.code == 1000001){
router.replace({
path: 'login'
})
return Promise.reject(res);
} else {
// 对响应数据做些什么
return res
}
}, err => {
// 对响应错误做些什么
console.log('err', err.response) // 修改后
return Promise.resolve(errsresponse) // 可在组件内获取到服务器返回信息
})
//使用钩子函数对路由进行权限跳转
router.beforeEach((to, from, next) => {
debugger
const userId = localStorage.getItem('ms_userId');
if (!userId && to.path !== '/login') {
next('/login');
} else if(to.path==="/login"){
next();
}else if (to.meta.permission) {
// 如果是管理员权限则可进入,这里只是简单的模拟管理员权限而已
userId === 'admin' ? next() : next('/403');
} else {
let userMenu = localStorage.getItem('user_menu');
if(!userMenu){
var params ={
userId : userId
}
axios.post('/sys/selectUserPermission', params ).then((res) => {
console.log(res.data)
if(res.data.success){
console.log(res.data.data)
userMenu = res.data.data;
localStorage.setItem('user_menu',res.data.data);
// 简单的判断IE10及以下不进入富文本编辑器,该组件不兼容
if (navigator.userAgent.indexOf('MSIE') > -1 && to.path === '/editor') {
Vue.prototype.$alert('vue-quill-editor组件不兼容IE10及以下浏览器,请使用更高版本的浏览器查看', '浏览器不兼容通知', {
confirmButtonText: '确定'
});
} else {
if(to.path !== '/403' && to.path !== '/login'&& userMenu){
let result = userMenu.indexOf(to.path);
if(result>=0){
next();
} else{
next('/403');
}
} else {
next();
}
}
} else {
Vue.prototype.$alert(res.data.msg, '错误提示', {
confirmButtonText: '确定'
});
}
})
} else {
// 简单的判断IE10及以下不进入富文本编辑器,该组件不兼容
if (navigator.userAgent.indexOf('MSIE') > -1 && to.path === '/editor') {
Vue.prototype.$alert('vue-quill-editor组件不兼容IE10及以下浏览器,请使用更高版本的浏览器查看', '浏览器不兼容通知', {
confirmButtonText: '确定'
});
} else {
if(to.path !== '/403' && to.path !== '/login'&& userMenu){
let result = userMenu.indexOf(to.path);
if(result>=0){
next();
} else{
next('/403');
}
} else {
next();
}
}
}
}
})
后端是自己搭建的springboot项目,数据库用的是mysql。数据库连接池用的druid,mybatis持久层框架,pagehelper分页插件。
<properties>
<java.version>1.8java.version>
<mybatis.version>1.3.2mybatis.version>
<pagehelper.version>1.2.3pagehelper.version>
<shiro.version>1.4.0shiro.version>
<fastjson.version>1.2.31fastjson.version>
<druid.version>1.1.10druid.version>
<swagger.version>2.5.0swagger.version>
<swagger.ui.version>2.5.0swagger.ui.version>
<commons.lang3.version>3.4commons.lang3.version>
<commons.beanutils.version>1.9.3commons.beanutils.version>
<shiro.redis.version>3.1.0shiro.redis.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>${mybatis.version}version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>${druid.version}version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>${fastjson.version}version>
dependency>
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelper-spring-boot-starterartifactId>
<version>${pagehelper.version}version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>${swagger.version}version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>${swagger.ui.version}version>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
<version>${commons.lang3.version}version>
dependency>
<dependency>
<groupId>commons-beanutilsgroupId>
<artifactId>commons-beanutilsartifactId>
<version>${commons.beanutils.version}version>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-springartifactId>
<version>${shiro.version}version>
dependency>
<dependency>
<groupId>org.crazycakegroupId>
<artifactId>shiro-redisartifactId>
<version>${shiro.redis.version}version>
<exclusions>
<exclusion>
<artifactId>shiro-coreartifactId>
<groupId>org.apache.shirogroupId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
<dependency>
<groupId>com.google.code.gsongroupId>
<artifactId>gsonartifactId>
dependency>
dependencies>
Apache的Shiro是一个非常易用的安全框架,提供了包括认证、授权、加密、会话管理等功能,与Spring Security一样属基于权限的安全框架,但是与Spring Security 相比,Shiro使用了比较简单易懂易于使用的授权方式。Shiro属于轻量级框架,相对于Spring Security简单很多,并没有security那么复杂。
- HopeShiroRealm 继承了AuthorizingRealm,这个类的作用是两处获取信息,一处是Subject即用户传过来的信息;一处是通过我们提供给shiro的SysUserService接口从数据库获取权限信息和角色信息。拿这两个信息之后AuthorizingRealm会自动进行比较,判断用户名密码,用户权限等等。拿用户凭证信息的是doGetAuthenticationInfo接口,拿角色权限信息的是doGetAuthorizationInfo接口。两个重要参数,AuthenticationToken是我们可以自己实现的用户凭证/密钥信息,PrincipalCollection是用户凭证信息集合。配置完成之后Subject.login(token)的时候就会调用doGetAuthenticationInfo方法;涉及到Subject.hasRole或者Subject.hasPermission的时候就会调用doGetAuthorizationInfo方法。
在配置shiro的拦截信息的时候,要忽略拦截"/" ,由于前端路由配置了根路径的路由,忽略拦截,会访问前端路由。
package com.lh.config.shiro;
import com.lh.common.HopeExceptionHandler;
import com.lh.config.properties.RedisInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerExceptionResolver;
import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;
@Slf4j
@Configuration
public class ShiroConfig {
/**
* Filter工厂,设置对应的过滤条件和跳转条件
*/
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
log.info("ShiroConfiguration.shirFilter()");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
//注意过滤器配置顺序 不能颠倒
//配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了,登出后跳转配置的loginUrl
filterChainDefinitionMap.put("/logout", "logout");
// 配置不会被拦截的链接 顺序判断
filterChainDefinitionMap.put("/static/**", "anon");
// 首页
filterChainDefinitionMap.put("/", "anon");
// 登录
filterChainDefinitionMap.put("/sys/login", "anon");
filterChainDefinitionMap.put("/**", "corsAuthenticationFilter");
//配置 shiro 默认登录界面地址,前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据
shiroFilterFactoryBean.setLoginUrl("/unauth");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
//自定义过滤器
Map<String, Filter> filterMap = new LinkedHashMap<>();
filterMap.put("corsAuthenticationFilter", new CORSAuthenticationFilter());
shiroFilterFactoryBean.setFilters(filterMap);
return shiroFilterFactoryBean;
}
/**
* 将自己的用户认证验证方式加入容器
*/
@Bean
public HopeShiroRealm hopeShiroRealm() {
return new HopeShiroRealm();
}
/**
* 权限管理,配置主要是Realm的管理认证 和session管理
*
* @param redisSessionManager redis session共享
* @param redisCacheManager redis 缓存
*/
@Bean
public SecurityManager securityManager(
@Qualifier("redisSessionManager") DefaultWebSessionManager redisSessionManager,
@Qualifier("redisCacheManager") RedisCacheManager redisCacheManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(hopeShiroRealm());
securityManager.setSessionManager(redisSessionManager);
securityManager.setCacheManager(redisCacheManager);
return securityManager;
}
/**
* 配置shiro redisManager
* 使用的是shiro-redis开源插件
*/
@Bean
public RedisManager redisManager(RedisInfo redisConfig) {
RedisManager redisManager = new RedisManager();
redisManager.setHost(redisConfig.getHost());
redisManager.setPort(redisConfig.getPort());
redisManager.setTimeout(redisConfig.getTimeout());
return redisManager;
}
/**
* redisSession相关配置
* 自定义session持久化
* 为啥session也要持久化?
* 重启应用,用户无感知,可以继续以原先的状态继续访问
* 注意点:
* DO对象需要实现序列化接口 Serializable
* logout接口和以前一样调用,请求logout后会删除redis里面的对应的key,即删除对应的token
*/
@Bean
public RedisSessionDAO redisSessionDAO(RedisManager redisManager) {
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(redisManager);
redisSessionDAO.setKeyPrefix("HOPE_SHIRO_SESSION:");// key
redisSessionDAO.setExpire(1000); // 过期时间
return redisSessionDAO;
}
/**
* session的管理 用redis实现session共享
*/
@Bean
public DefaultWebSessionManager redisSessionManager(RedisSessionDAO redisSessionDAO) {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionDAO(redisSessionDAO);
return sessionManager;
}
/**
* 配置具体cache实现类RedisCacheManager
* 为什么要使用缓存:
* 缓存组件位于SecurityManager中,在HopeShiroRealm数据域中,由于授权方法中每次都要查询数据库,性能受影响,因此将数据缓存起来,提高查询效率
* 除了使用Redis缓存,还能使用shiro-ehcache
*/
@Bean
public RedisCacheManager redisCacheManager(RedisManager redisManager) {
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(redisManager);
return redisCacheManager;
}
/**
* 加入注解的使用,不加入这个注解不生效
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* 注册全局异常处理
*/
@Bean(name = "exceptionHandler")
public HandlerExceptionResolver handlerExceptionResolver() {
return new HopeExceptionHandler();
}
}
package com.lh.config.shiro;
import com.lh.entity.sys.SysPermission;
import com.lh.entity.sys.SysRole;
import com.lh.entity.sys.SysUser;
import com.lh.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import javax.annotation.Resource;
/**
* 实现AuthorizingRealm接口用户认证
*/
@Slf4j
public class HopeShiroRealm extends AuthorizingRealm {
@Resource
private SysUserService sysUserService;
/**
* 角色权限和对应权限添加
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
log.info("权限配置-->HopeShiroRealm.doGetAuthorizationInfo()");
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
SysUser sysUser = (SysUser) principals.getPrimaryPrincipal();
for (SysRole role : sysUser.getSysRoles()) {
// 添加角色
authorizationInfo.addRole(role.getRoleId());
for (SysPermission p : role.getSysPermissions()) {
// 添加权限
authorizationInfo.addStringPermission(p.getPermission());
}
}
return authorizationInfo;
}
/**
* 主要是用来进行身份认证的,也就是说验证用户输入的账号和密码是否正确。
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
log.info("HopeShiroRealm.doGetAuthenticationInfo()");
//获取用户的输入的账号.
String userId = (String) token.getPrincipal();
log.info("用户密码 ={}", token.getCredentials());
//通过username从数据库中查找 User对象,如果找到,没找到.
//实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
SysUser sysUser = sysUserService.selectSysUserByUserId(userId);
log.info("----->>sysUser=" + sysUser);
if (sysUser == null) {
return null;
}
if (sysUser.getStatus() == 1) { //账户冻结
throw new LockedAccountException();
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
sysUser, //用户名
sysUser.getPassword(), //密码
null,
//ByteSource.Util.bytes(sysUser.getCredentialsSalt()),//salt=username+salt
getName() //realm name
);
return authenticationInfo;
}
}
前后端分离项目中,由于跨域,会导致复杂请求,即会发送preflighted request,这样会导致在GET/POST等请求之前会先发一个OPTIONS请求,但OPTIONS请求并不带cookie,即OPTIONS请求不能通过shiro验证,会返回未认证的信息。
package com.lh.config.shiro;
import com.alibaba.fastjson.JSON;
import com.lh.entity.common.Result;
import com.lh.common.enums.TransactionCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
@Slf4j
public class CORSAuthenticationFilter extends FormAuthenticationFilter {
@Override
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
//Always return true if the request's method is OPTIONSif (request instanceof HttpServletRequest) {
if (((HttpServletRequest) request).getMethod().toUpperCase().equals("OPTIONS")) {
return true;
}
return super.isAccessAllowed(request, response, mappedValue);
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
HttpServletResponse res = (HttpServletResponse) response;
res.setHeader("Access-Control-Allow-Origin", "*");
res.setStatus(HttpServletResponse.SC_OK);
res.setCharacterEncoding("utf-8");
PrintWriter writer = res.getWriter();
writer.write(JSON.toJSONString(Result.error(TransactionCode.NO_LOGION.getCode(), TransactionCode.NO_LOGION.getMsg())));
writer.close();
return false;
}
}
package com.lh.controller;
import com.lh.entity.sys.SysUser;
import com.lh.entity.common.Result;
import com.lh.common.enums.TransactionCode;
import com.lh.entity.sys.common.UserMenu;
import com.lh.service.SysService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
@Slf4j
@RestController
public class SysController {
@Resource
private SysService sysService;
/**
* 登录方法
*
* @param sysUser
* @return
*/
@RequestMapping(value = "/sys/login", method = RequestMethod.POST)
public Result ajaxLogin(@RequestBody SysUser sysUser) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(sysUser.getUserId(), sysUser.getPassword());
try {
subject.login(token);
return Result.ok(subject.getSession().getId());
} catch (IncorrectCredentialsException e) {
return Result.error("密码错误!");
} catch (LockedAccountException e) {
return Result.error("登录失败,该用户已被冻结!");
} catch (AuthenticationException e) {
return Result.error("该用户不存在!");
} catch (Exception e) {
log.info("用户登录时发生异常!e={}", e);
return Result.error();
}
}
/**
* 未登录,shiro应重定向到登录界面,此处返回未登录状态信息由前端控制跳转页面
*
* @return
*/
@RequestMapping(value = "/unauth")
public Result<String> unauth() {
return Result.error(TransactionCode.NO_LOGION.getCode(), TransactionCode.NO_LOGION.getMsg());
}
/**
* 根据用户编号查询用户所有菜单
*
* @param sysUser
* @return
*/
@RequestMapping(value = "/sys/selectUserMenu", method = RequestMethod.POST)
public Result<List<UserMenu>> selectUserMenu(@RequestBody SysUser sysUser) {
// 根据用户编号查询用户所有可见菜单
if (StringUtils.isNotBlank(sysUser.getUserId())) {
return sysService.selectUserMenu(sysUser.getUserId());
} else {
return Result.error("未获取到当前登录人信息!");
}
}
@RequestMapping(value = "/sys/selectUserPermission", method = RequestMethod.POST)
public Result<List<String>> selectUserPermission(@RequestBody SysUser sysUser) {
if (StringUtils.isNotBlank(sysUser.getUserId())) {
return sysService.selectUserPermission(sysUser.getUserId());
} else {
return Result.error("未获取到当前登录人信息!");
}
}
}
将构建好的dist下static文件夹拷贝到springboot的resource的static下,index.html也拷贝到springboot的resource的static下。