写一个简易的java项目(四) 登陆和权限

摘要:
打印日志和`account`varchar(50)CHARACTERSETutf8COLLATEutf8_ general_ CiDEFAULTNULLCOMMENT'帐户',`password ` varchar(40)CHARACHERSETutf8COLLATEUtf8 _ general_CiDEFAULT NULLCOMMENT'密码',

用到的技术:

  后台: java (springboot+shiro) 。创建项目-可参考 写一个简易的java项目(一)

  前台: vue-admin-template (前台权限参考vue-element-admin)。下载配置-可参考 写一个简易的java项目(三)

编辑器:

  后台:IntelliJ IDEA 

  前台:Visual Studio Code

后台:

第一步:打印日志 &确认前台传过来的参数:账号密码

 这里我使用fastjson的方法 获取用户密码,代码如下

写一个简易的java项目(四) 登陆和权限第1张

pom:

写一个简易的java项目(四) 登陆和权限第2张写一个简易的java项目(四) 登陆和权限第3张
    <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
View Code

 登陆打印结果:

写一个简易的java项目(四) 登陆和权限第4张

第二步: 这里我们先创建三张表:

因为只是登陆 还没到权限所以 主要是用户表: 存一些基本信息如 账号 密码 头像 密码盐(如果需要的话) 角色id

  sys_user 用户

  sys_role 角色

  sys_permission 权限

用户表:

写一个简易的java项目(四) 登陆和权限第5张写一个简易的java项目(四) 登陆和权限第6张
CREATE TABLE `sys_user` (
  `user_id` bigint NOT NULL COMMENT '主键id',
  `avatar` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '头像',
  `account` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '账号',
  `password` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '密码',
  `salt` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '密码盐',
  `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '名字',
  `birthday` datetime DEFAULT NULL COMMENT '生日',
  `sex` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '性别',
  `email` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '邮箱',
  `phone` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '电话',
  `role_ids` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '角色id(多个逗号隔开)',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `create_user` bigint DEFAULT NULL COMMENT '创建人',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  `update_user` bigint DEFAULT NULL COMMENT '更新人',
  PRIMARY KEY (`user_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='用户表';
View Code

角色表:

写一个简易的java项目(四) 登陆和权限第7张写一个简易的java项目(四) 登陆和权限第8张
CREATE TABLE `sys_role` (
  `role_id` bigint NOT NULL COMMENT '主键id',
  `pid` bigint DEFAULT NULL COMMENT '父角色id',
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '角色名称',
  `description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '描述',
  `sort` int DEFAULT NULL COMMENT '序号',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '修改时间',
  `create_user` bigint DEFAULT NULL COMMENT '创建用户',
  `update_user` bigint DEFAULT NULL COMMENT '修改用户',
  `deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
  PRIMARY KEY (`role_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='角色表';
View Code

权限表:

写一个简易的java项目(四) 登陆和权限第9张写一个简易的java项目(四) 登陆和权限第10张
CREATE TABLE `sys_permission` (
  `id` int NOT NULL AUTO_INCREMENT,
  `role_id` int DEFAULT NULL COMMENT '角色ID',
  `permission` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '权限',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  `deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT COMMENT='权限表';
View Code

第三步:shiro 权限认证

  1.pom:

    <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-web-starter</artifactId>
            <version>1.4.0</version>
        </dependency>

   2.自定义Realm 主要作用有:验证登陆人的账号密码是否正确、验证账号的权限信息等等

   extends AuthorizingRealm 重写两个方法:

      doGetAuthorizationInfo(PrincipalCollection principalCollection) 

      doGetAuthenticationInfo(AuthenticationToken authenticationToken) 

   写一个简易的java项目(四) 登陆和权限第11张

KingRealm

 第一个方法:授权:这里需要写一些方法->通过角色id 获取角色名称 和 权限信息

  /**
     * 权限认证
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 获取用户
        User user = (User) principalCollection.getPrimaryPrincipal();
        String roleIds = user.getRoleIds();

        // 通过角色id获取用户权限
        Set<String> roles = roleService.getRolesByRoleIds(roleIds);
        Set<String> permissions = permissionService.getPermissionsByRoleIds(roleIds);

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(roles);
        info.setStringPermissions(permissions);
        return info;
    }

   service

public Set<String> getPermissionsByRoleIds(String roleIds) {
        Set<String> permissions = new HashSet<String>();
        if (StringUtils.isEmpty(roleIds)) {
            return permissions;
        }

        List<Permission> permissionList = permissionMapper.getPermissionsByRoleIds(roleIds);

        for (Permission permission : permissionList) {
            permissions.add(permission.getPermission());
        }

        return permissions;
}

第二个方法:认证:这里需要一个方法-》就是通过账号获取用户信息 

  /**
     * 登录认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username = token.getUsername();
        String password = new String(token.getPassword());

        if (StringUtils.isEmpty(username)) {
            throw new AccountException("用户名不能为空");
        }
        if (StringUtils.isEmpty(password)) {
            throw new AccountException("密码不能为空");
        }

        // 根据用户名从数据库中查询该用户
        User user = userService.getByUsername(username);
        if(user == null) {
            throw new UnknownAccountException("账号或密码不正确");// 不存在该账号
        }
        // 验证账号密码是否正确 这里使用 :Md5(token密码+盐) = 数据库密码 的方式
        String requestPassword = SaltMd5Util.toMd5String(password, user.getSalt());// token 中的password
        String dbPassword = user.getPassword();// 数据库中的 password
        if (dbPassword == null || !dbPassword.equalsIgnoreCase(requestPassword)) {
            throw new UnknownAccountException("账号或密码不正确");
        }
        // 把当前用户存到 Session 中
        SecurityUtils.getSubject().getSession().setAttribute("user", user);
        // 传入用户名和密码进行身份认证,并返回认证信息
        AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user, password, getName());
        return authcInfo;

    }

  加密util:

public static String toMd5String(String password, String salt) {
        String secret = password+salt;
        return DigestUtils.md5DigestAsHex(secret.getBytes());
}

  3.shiro 配置 ShiroConfig

    首先把我们刚刚写好的Realm 引进来:

@Configuration
public class ShiroConfig {

    @Bean
    public KingRealm KingRealm() {return new KingRealm(); }
}

    加上shiro 过滤器:

  /**
     * shiro过滤器
     * @param securityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 拦截器
        // anon 不会拦截
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        filterChainDefinitionMap.put("/user/logout", "anon");
        filterChainDefinitionMap.put("/user/login", "anon");
        // authc 拦截
        filterChainDefinitionMap.put("/**", "authc");
        // 默认登录页面地址
        shiroFilterFactoryBean.setLoginUrl("/user/login");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    加上安全管理器:

  /**
     * 安全管理器
     * @return
     */
    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(KingRealm());return securityManager;
    }

  注解权限控制:

  切点:

  @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

  切面:

  @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public static DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }

第四步:写登陆、获取用户信息、退出登录 三个后台接口

登陆:

   @ResponseBody
    @PostMapping("/login")
    public ResponseData login(@RequestBody String body) {
        log.info("===登陆请求===请求参数为body:{}",body);
        JSONObject json=JSONObject.parseObject(body);

        String username= (String) json.get("username");
        String password= (String) json.get("password");

        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            return ResponseData.error("账号、密码不能为空");
        }

        Subject currentUser = SecurityUtils.getSubject();// 获取当前用户信息
        if (!currentUser.isAuthenticated()) {
            UsernamePasswordToken token = new UsernamePasswordToken(username,password);
            try {
                currentUser.login(token);
            } catch (UnknownAccountException uae) {
                log.error("===登陆请求===错误:{}", "账号或密码错误");
                return ResponseData.error("账号或密码错误");
            } catch (Exception e) {
                log.error("===登陆请求===错误:{}", "账号或密码错误");
                return ResponseData.error("账号或密码错误");
            }
        }

        log.info("返回结果:{}", JSONObject.toJSONString(currentUser.getSession().getId()));
        return ResponseData.success(currentUser.getSession().getId());
    }

获取用户信息:

   @ResponseBody
    @RequestMapping("/info")
    public ResponseData info() {
        Subject currentUser = SecurityUtils.getSubject();
        User user = (User) currentUser.getPrincipal();

        Map<String, Object> data = new HashMap<>();
        data.put("name", user.getAccount());
        data.put("avatar", user.getAvatar());

        String roleIds = user.getRoleIds();

        // 通过角色id获取用户权限
        Set<String> roles = roleService.getRolesByRoleIds(roleIds);
        Set<String> permissions = permissionService.getPermissionsByRoleIds(roleIds);
        data.put("roles", roles);
        data.put("permissions", permissions);

        log.info("用户信息:{}", JSONObject.toJSONString(data));
        return ResponseData.success(data);
  }

退出登录:

   @ResponseBody
    @PostMapping("/logout")
    public ResponseData login() {
        Subject currentUser = SecurityUtils.getSubject();
        currentUser.logout();

        log.info("===退出登录===:{}", JSONObject.toJSONString(currentUser.getSession().getId()));
        return ResponseData.success();
    }

看一下测试效果:

失败:

写一个简易的java项目(四) 登陆和权限第12张 

 控制台输出:

写一个简易的java项目(四) 登陆和权限第13张

 成功:

写一个简易的java项目(四) 登陆和权限第14张

控制台输出:

写一个简易的java项目(四) 登陆和权限第15张

 点击退出->

回到了登录页面

控制台输出:

写一个简易的java项目(四) 登陆和权限第16张

这是我之前的测试页面,做了简单的增删改查:

写一个简易的java项目(四) 登陆和权限第17张

 怎样给admin 这个用户添加权限?

 后台:

直接加注解看看:

写一个简易的java项目(四) 登陆和权限第18张

 ###如果出现这种问题:

写一个简易的java项目(四) 登陆和权限第19张

404

 写一个简易的java项目(四) 登陆和权限第20张

 解决一下这个问题:原因是 在ShiroConfig 中少加了代码:

  @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public static DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }

###

前台:

###插曲 -了解一下vue-admin-template 的登陆验证  > <。

它用到了vuex, 什么是vuex?-》》vuex 学习笔记

这里我改了个东西:

  登录的返回值。因为后台我直接返回了token ,所以这里把 .token 去掉了 。不需要盲目的改 看自己返回的结果。

写一个简易的java项目(四) 登陆和权限第21张

 这样我们就可以通过 getToken() 获取到token 了。

 写一个简易的java项目(四) 登陆和权限第22张

 而我们在permission.js 的 router.beforeEach 方法中 (路由拦截) 调用了此方法,判断用户是否登陆过了。

写一个简易的java项目(四) 登陆和权限第23张

 #main.js 中可以看到引入了权限=》 permission.js 

 写一个简易的java项目(四) 登陆和权限第24张

 写一个简易的java项目(四) 登陆和权限第25张

 ###

其实既然没有权限就没必要显示出来 -》

菜单权限:

看一下permission.js 中路由拦截的方法:

router.beforeEach(async(to, from, next) => {
  // start progress bar
  NProgress.start()

  // set page title
  document.title = getPageTitle(to.meta.title)

  // determine whether the user has logged in
  const hasToken = getToken()

  if (hasToken) {// 如果存在token
    if (to.path === '/login') {
      // if is logged in, redirect to the home page
      next({ path: '/' })
      NProgress.done()
    } else {
      const hasGetUserInfo = store.getters.name
      if (hasGetUserInfo) {// 如果store中存在用户名
        next()
      } else {
        try {
          // get user info 获取用户信息
          await store.dispatch('user/getInfo')

          next()
        } catch (error) {
          // remove token and go to login page to re-login
          await store.dispatch('user/resetToken')
          // Message.error(error || 'Has Error')
          Message.error(error || 'Has Error')
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      }
    }
  } else {// 没有token
    /* has no token*/

    if (whiteList.indexOf(to.path) !== -1) {// 白名单免登陆
      // in the free login whitelist, go directly
      next()
    } else {// 重定向到首页
      // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }
})

思路:获取用户信息后把权限信息也存起来,然后处理菜单只显示有权限的菜单。

第一步:获取后台的权限信息

  看一下前台可以不可获取用户的权限信息,如果可以 我们需要把权限信息存起来。 

  用户信息存放的位置在-vuex:src/store/modules/user.js 

state中定义两个变量roles 和permissions 分别存后台传过来的角色名称和权限。

mutations 写好对应的方法,以便调用赋值。

写一个简易的java项目(四) 登陆和权限第26张

 getters

写一个简易的java项目(四) 登陆和权限第27张

后台传过来的值:

  打印了一下 getInfo 返回的data,大概是这样 :

写一个简易的java项目(四) 登陆和权限第28张

 找到getInfo方法 给这两个参数赋值。在退出登录时清空。

写一个简易的java项目(四) 登陆和权限第29张

第二步:处理菜单只显示有权限的部分

这里为了省事,就直接把 vue-element-admin 中的代码粘过来,改一改好了。o.o

首先是:permission.js 

写一个简易的java项目(四) 登陆和权限第30张

  然后是store->permission

写一个简易的java项目(四) 登陆和权限第31张

  然后是index

写一个简易的java项目(四) 登陆和权限第32张

  getter

写一个简易的java项目(四) 登陆和权限第33张

 改动:

  第一步:由于我想用权限信息 permissions 来确定菜单,而不是用户的角色。所以过滤菜单的方法传参 传permissions。

写一个简易的java项目(四) 登陆和权限第34张

   同理,permission.js 中所有的role 都改成了permission 也是为了代码的可读性。

写一个简易的java项目(四) 登陆和权限第35张

  第二步: permission.js 中传的参数 asyncRoutes 

 写一个简易的java项目(四) 登陆和权限第36张

  不需要权限的:

写一个简易的java项目(四) 登陆和权限第37张

   需要权限的:为了测试,现在把测试菜单放到这下面:

 写一个简易的java项目(四) 登陆和权限第38张

 现在 router 中的代码:

写一个简易的java项目(四) 登陆和权限第39张写一个简易的java项目(四) 登陆和权限第40张
import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

/* Layout */
import Layout from '@/layout'

/**
 * Note: sub-menu only appear when route children.length >= 1
 * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
 *
 * hidden: true                   if set true, item will not show in the sidebar(default is false)
 * alwaysShow: true               if set true, will always show the root menu
 *                                if not set alwaysShow, when item has more than one children route,
 *                                it will becomes nested mode, otherwise not show the root menu
 * redirect: noRedirect           if set noRedirect will no redirect in the breadcrumb
 * name:'router-name'             the name is used by <keep-alive> (must set!!!)
 * meta : {
    roles: ['admin','editor']    control the page roles (you can set multiple roles)
    title: 'title'               the name show in sidebar and breadcrumb (recommend set)
    icon: 'svg-name'             the icon show in the sidebar
    breadcrumb: false            if set false, the item will hidden in breadcrumb(default is true)
    activeMenu: '/example/list'  if set path, the sidebar will highlight the path you set
  }
 */

/**
 * constantRoutes
 * a base page that does not have permission requirements
 * all roles can be accessed
 */
export const constantRoutes = [
  {
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true
  },

  {
    path: '/404',
    component: () => import('@/views/404'),
    hidden: true
  },

  {
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    children: [{
      path: 'dashboard',
      name: 'Dashboard',
      component: () => import('@/views/dashboard/index'),
      meta: { title: '首页', icon: 'dashboard' }
    }]
  }

  // 404 page must be placed at the end !!!
  // { path: '*', redirect: '/404', hidden: true }
]

export const asyncRoutes = [
  {
    path: '/example',
    component: Layout,
    redirect: 'noredirect',
    alwaysShow: true,
    name: 'Example',
    meta: {
      permissions: ['/example'],
      title: '测试',
      icon: 'example' },
    children: [
      {
        path: 'table',
        name: '表格',
        component: () => import('@/views/mytable/index'),
        meta: {
          permissions: ['/example/table'],
          title: '测试表格',
          icon: 'table'
        }
      },
      {
        path: 'other',
        name: '其他',
        component: () => import('@/views/table/index'),
        meta: {
          permissions: ['/example/other'],
          title: '测试其他',
          icon: 'table'
        }
      }
    ]
  },
  // 404 page must be placed at the end !!!
  { path: '*', redirect: '/404', hidden: true }
]

const createRouter = () => new Router({
  // mode: 'history', // require service support
  scrollBehavior: () => ({ y: 0 }),
  routes: constantRoutes
})

const router = createRouter()

// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // reset router
}

export default router
View Code

@/permission.js 中代码

写一个简易的java项目(四) 登陆和权限第41张写一个简易的java项目(四) 登陆和权限第42张
import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'

NProgress.configure({ showSpinner: false }) // NProgress Configuration

const whiteList = ['/login'] // no redirect whitelist

router.beforeEach(async(to, from, next) => {
  // start progress bar
  NProgress.start()

  // set page title
  document.title = getPageTitle(to.meta.title)

  // determine whether the user has logged in
  const hasToken = getToken()

  if (hasToken) {
    if (to.path === '/login') {
      // if is logged in, redirect to the home page
      next({ path: '/' })
      NProgress.done()
    } else {
      const hasGetUserInfo = store.getters.name
      if (hasGetUserInfo) {
        next()
      } else {
        try {
          // store.dispatch('user/getInfo')
          // next()
          store.dispatch('user/getInfo').then(res => {
            // generate accessible routes map based on roles
            store.dispatch('permission/generateRoutes', res.permissions).then(() => {
              // dynamically add accessible routes
              debugger
              router.addRoutes(store.getters.addRoutes)
              // hack method to ensure that addRoutes is complete
              // set the replace: true, so the navigation will not leave a history record
              next({ ...to, replace: true })
            })
          })
        } catch (error) {
          // remove token and go to login page to re-login
          await store.dispatch('user/resetToken')
          // Message.error(error || 'Has Error')
          Message.error(error || 'Has Error')
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      }
    }
  } else {
    /* has no token*/

    if (whiteList.indexOf(to.path) !== -1) {
      // in the free login whitelist, go directly
      next()
    } else {
      // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }
})

router.afterEach(() => {
  // finish progress bar
  NProgress.done()
})
View Code

   第三步:渲染 -》 改成自己的 ok!

 写一个简易的java项目(四) 登陆和权限第43张

 数据库:

用户:

写一个简易的java项目(四) 登陆和权限第44张

 权限

写一个简易的java项目(四) 登陆和权限第45张

效果:

写一个简易的java项目(四) 登陆和权限第46张

 按钮权限:

同理为了方便,我们把vue-element-admin 中的utils/permission.js 粘贴过来,做个简单修改。

第一步,粘贴

写一个简易的java项目(四) 登陆和权限第47张

 同样,把roles 改成permissions

第二步:粘贴 @/directive/permission/index.js  权限判断指令

写一个简易的java项目(四) 登陆和权限第48张

 同样,把role 改成permission

写一个简易的java项目(四) 登陆和权限第49张

 main.js

import permission from '@/directive/permission/index.js' // 权限判断指令
Vue.directive('permission', permission)

写一个简易的java项目(四) 登陆和权限第50张

 页面:

写一个简易的java项目(四) 登陆和权限第51张

 没有权限时:

写一个简易的java项目(四) 登陆和权限第52张

 有权限时:

写一个简易的java项目(四) 登陆和权限第53张

 数据库:

写一个简易的java项目(四) 登陆和权限第54张

 解决问题&补充:

 问题一:把前台打包放到项目下启动后出现如下错误:

写一个简易的java项目(四) 登陆和权限第55张

 排查错误引发原因得出结论:是shiro 拦截引起的。

Uncaught SyntaxError: Unexpected token '<'

解决方案:放过static 下的静态文件即可

filterChainDefinitionMap.put("/static/**", "anon");

写一个简易的java项目(四) 登陆和权限第56张

 问题二:在本地启动没有问题,打包后就出现如下问题:

写一个简易的java项目(四) 登陆和权限第57张

 可能导致这个问题的原因有很多。这里我的问题竟然是:。。。 clean 之后直接打包导致的。

2020-10-10 15:11:41.962  INFO 8784 --- [ost-startStop-1] ConditionEvaluationReportLoggingListener :

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-10-10 15:11:41.966 ERROR 8784 --- [ost-startStop-1] o.s.b.d.LoggingFailureAnalysisReporter   :

***************************
APPLICATION FAILED TO START
***************************

Description:

Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.

Reason: Failed to determine a suitable driver class


Action:

Consider the following:
        If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
        If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).

 正确的操作应该是 clean ->build->package 

写一个简易的java项目(四) 登陆和权限第58张

问题三: 退出登录之后,点击菜单时:url 虽然改变了,但页面空白。点击 enter 刷新后 又可显示页面。。

解决方案:

写一个简易的java项目(四) 登陆和权限第59张

代码:

await this.$store.dispatch('user/logout').then(() => {
        location.reload()
})

问题四:获取用户信息失败时,跳到登录页避免bug

写一个简易的java项目(四) 登陆和权限第60张

 代码:

store.dispatch('user/getInfo').then(res => {
          // generate accessible routes map based on roles
          store.dispatch('permission/generateRoutes', res.permissions).then(() => {
              // dynamically add accessible routes
              router.addRoutes(store.getters.addRoutes)
              // hack method to ensure that addRoutes is complete
              // set the replace: true, so the navigation will not leave a history record
              next({ ...to, replace: true })
            })
          }).catch((error) => {
            store.dispatch('user/resetToken').then(() => {
              Message.error(error || '请重新登陆')
              next({ path: '/' })
          })
})

补充一:在控制台打印mybatis SQL 语句

logging:
  level:
    com.example.king:  DEBUG

控制台输出:

写一个简易的java项目(四) 登陆和权限第61张

 补充二:配置 swagger 

自动生成在线开发文档,方便测试等优点

 pom

    <!--swagger-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

配置:

写一个简易的java项目(四) 登陆和权限第62张

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.any())// 限制包
                .paths(PathSelectors.any())// 限制控制器
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("King")
                .description("king-接口文档")
                .contact("DarGi")
                .version("1.0")
                .build();
    }
}

shiroConfig 中放行:

     filterChainDefinitionMap.put("/swagger-ui.html", "anon");
        filterChainDefinitionMap.put("/swagger/**", "anon");
        filterChainDefinitionMap.put("/swagger-resources/**", "anon");
        filterChainDefinitionMap.put("/v2/**", "anon");
        filterChainDefinitionMap.put("/webjars/**", "anon");
        filterChainDefinitionMap.put("/configuration/**", "anon");

页面:http://localhost:8091/swagger-ui.html#/

写一个简易的java项目(四) 登陆和权限第63张

写一个简易的java项目(四) 登陆和权限第64张

 做个测试:

写一个简易的java项目(四) 登陆和权限第65张

 返回结果

写一个简易的java项目(四) 登陆和权限第66张

@

免责声明:文章转载自《写一个简易的java项目(四) 登陆和权限》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇域控制器指派或发布软件不成功原因C++ map容器在const修饰下将无法使用"[]"来获取键值 (转)passing ‘’ as ‘xx’ argument discards qualifiers [-fpermissive]下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Oracle查看和修改连接数

  1.查询数据库当前进程的连接数:   select count(*) from v$process;   2.查看数据库当前会话的连接数:   elect count(*) from v$session;   3.查看数据库的并发连接数:   select count(*) from v$session where status='ACTIVE';  ...

微软Sharepoint的一些缺点

转:http://bbs.tianya.cn/post-144-566491-1.shtml 微软Sharepoint的一些缺点(一) 微软Sharepoint的一些缺点      关于SharePoint,它是在文档管理平台上构建起来的,加入简单工作流功能的web系统。它完全基于微软体系架构,好处是与Office结合紧密,缺点是兼容性不够,过分依赖微软运...

VBS创建文件

在桌面创建文件 文件名称为0.txt到5.txt 桌面 & 1.txt = 桌面1.txt才是在桌面删除文件1.txt Administrator桌面 & 1.txt = Administrator桌面1.txt,在Administrator文件夹下删除的文件名是桌面1.txt dim file,fileContent di...

Python基础之列表

列表初识 列表的作用和定义 列表是python中使用最频繁的数据类型,在其他语言中一般称为数组; 用一个变量存储多个数据; 列表存储多个数据时,在中括号之间用逗号分隔多个数据; 语法定义: 变量名 = [数据1, 数据2, 数据3,...] eg: name_list = ["zhangsan", "lisi", "wangwu"] 列表存储数据的方式和...

RT-Thread代码启动过程——以及 $Sub$ $main 与 $Super$ $main

【转】https://blog.csdn.net/yang1111111112/article/details/80913001 我们找到系统复位的地方,可以往下单步跟踪。 ①从系统初始化开始执行,将函数地址赋给R0寄存器,跳转到R0地址执行并返回此处(BLX是带链接的跳转,即带返回的跳转)。 ②将main函数地址给R0,将函数地址赋给R0,跳转到R0地址...

Exchange 2016高可用及容灾架构选型参考

Exchange 2016高可用及容灾架构选型参考 钟云福 一     摘要 Exchange 2016作为微软最新最先进的企业级邮件系统,推出已一年多,由于其先进的架构,一脉相承的优秀办公体验,逐步被越来越多的企业所接受。嘉为科技今年已为几个中大规模的企业提供了Exchange 2016实施落地的项目,在方案确定过程中,经常需要讨论邮件架构的规划,现将规...