项目日记(在线办公项目)day2021/02/25

项目日记day0225

一、登录视图跳转的改进

方法一:使用响应拦截器

我们可以这样做:

在这里插入图片描述

在前端加一个响应拦截器,后端资源给的所有响应都会经过响应拦截器,可以只在响应拦截器中做一下"unlogin"字符串的判断,通过响应拦截器来做统一的视图跳转

响应拦截器是axios的一大特色之一。

在前端项目中的main.js加入以下代码:

// 添加响应拦截器
Vue.prototype.$axios.interceptors.response.use(response => {
  let result = response.data;
  if(result.loginSign == false){
    Vue.prototype.$swal.fire({
      icon: 'error',
      title: "用户未登录,请登陆后访问!",
      showConfirmButton: false,
      timer: 1500,
      onClose:()=>{
        router.push("/");//在main.js中可以直接使用router
      }
    })
  }
  return response;
});

进行测试,未登录的情况下访问"http://localhost:8080/#/main/main"点击测试按钮:

在这里插入图片描述

页面进行未登录提示,并跳转到登录页。

现在我们进行这么一个测试:输入后端中的一个控制器地址:http://localhost/jiazhong-office/login/unLogin,发现给我们响应的是json数组,而不是直接跳转到登陆页面。这是因为响应拦截器拦截的是从前端发出来请求后给予的响应,此时,我们只是直接在地址栏上输入了请求的地址,所以不会跳转到登录页面。

方法二:使用axios的请求拦截器与取消请求

我们可以这样做:

在这里插入图片描述

在前端设立一个请求拦截器,前端所有的请求都会经过请求拦截器,当请求拦截器检测到用户未登录时,会直接将视图跳转到登录视图上,检测到用户已登陆,将请求发送到后端。

这里有两种实现方式:

1.将用户登陆状态存入sessionStorage中(推荐使用)

  • 登陆成功后,像浏览器中存入"sessionStorage=true"的键值对

在这里插入图片描述

  • 添加请求拦截器(虽然拦截了请求,但只是做了一个表面上的样子,实际上请求还是发出去了)

在这里插入图片描述

  • 用户未登录,取消请求

在这里插入图片描述

  • 将SpringScurity配置的loginPage改为"http://localhost:8080"

在这里插入图片描述

  • 进行未登录测试,访问前端"http://localhost:8080/#/main/mian",点击测试按钮,提示后跳转到登录页;访问后端"localhost/jiazhong-office/test",直接跳转到前端登录页。测试成功!

2.使用全局变量表示用户登陆状态

  • 在main.js中设置全局变量token为false(注意:这里不能以Vue.prototype.$token=false来表示,因为这样是注册原型属性,原型属性只能被读,不能被修改)

在这里插入图片描述

  • 登陆成功后,将token属性修改为true

在这里插入图片描述

  • 在main.js中的请求拦截器中判断,如果token的属性为true则取消请求
    在这里插入图片描述

  • 测试成功!

二、权限角色在数据库中获取

我们之前对于用户角色是以将其写为固定的角色来进行处理的,但是在实际的业务中,角色是在数据库中获取的。

1.建立角色实体类并在在账户实体类中加入一个角色的List集合

package com.jiazhong.office.model;

/**
 * @ClassName: Role
 * @Description: TODO
 * @Author: JiaShiXi
 * @Date: 2021/2/25 13:23
 * @Version: 1.0
 **/

public class Role {
    private Integer role_id;
    private String role_name;
    private String role_desc;

    public Integer getRole_id() {
        return role_id;
    }

    public void setRole_id(Integer role_id) {
        this.role_id = role_id;
    }

    public String getRole_name() {
        return role_name;
    }

    public void setRole_name(String role_name) {
        this.role_name = role_name;
    }

    public String getRole_desc() {
        return role_desc;
    }

    public void setRole_desc(String role_desc) {
        this.role_desc = role_desc;
    }
}

在这里插入图片描述

2.利用关联映射,映射Account中的roles属性的值

AccountDao:

package com.jiazhong.office.dao.rbac;

import com.jiazhong.office.model.Account;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;

/**
 * @InterfaceName: AccountDao
 * @Description: TODO 账户持久层
 * @Author: JiaShiXi
 * @Date: 2021/2/23 20:29
 * @Version: 1.0
 **/
@Repository
public interface AccountDao {

    /**
     * 通过账户名查询账户信息
     * @param account_name 账户名
     * @return 账户对象
     */
    @Select("select * from tbl_account where account_name = #{account_name}")
    @Results(
            @Result(
                    property = "roles", //映射的属性
                    column = "account_id", //映射的字段
                    javaType = java.util.List.class, //映射属性的java类型
                    many = @Many(select = "com.jiazhong.office.dao.rbac.RoleDao.getRoleByAccountId") //多方使用的sql语句
            )
    )
    public Account queryAccountByAccountName(@Param("account_name") String account_name);
}

RoleDao:

package com.jiazhong.office.dao.rbac;

import com.jiazhong.office.model.Role;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

/**
 * @InterfaceName: RoleDao
 * @Description: TODO
 * @Author: JiaShiXi
 * @Date: 2021/2/25 13:31
 * @Version: 1.0
 **/
public interface RoleDao {

    /**
     * 通过账户ID查询用户所拥有的角色
     * @param account_id
     * @return
     */
    @Select("select * from tbl_role where role_id in(select role_id from tbl_account_role where account_id=#{account_id})")
    public Role getRoleByAccountId(@Param("account_id") Integer account_id);
}

3.修改userDetailServiceImpl类

package com.jiazhong.office.service.rbac;

import com.jiazhong.office.dao.rbac.AccountDao;
import com.jiazhong.office.model.Account;
import com.jiazhong.office.model.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName: UserDetailServiceImpl
 * @Description: TODO
 * @Author: JiaShiXi
 * @Date: 2021/2/23 20:26
 * @Version: 1.0
 **/

@Service("userDetailsService")
@Transactional
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private AccountDao accountDao;

    /**
     * 根据用户名获得用户信息
     *
     * @param username 用户名
     * @return 用户信息
     * @throws UsernameNotFoundException 用户名不存在异常
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Account account = accountDao.queryAccountByAccountName(username);
        if (account == null){
            throw new UsernameNotFoundException("账户名不存在");
        }

        //获取用户角色信息
        List<GrantedAuthority> grantedAuthorities = getGrantedAuthorities(account.getRoles());

        /**
         * 创建UserDetails实现类对象User,将认证信息传给User对象进行认证
         * 参数1:要认证用户的用户名
         * 参数2:要认证用户的密码
         * 参数3:要认证用户所拥有的权限集合
         */
        //User userAuth = new User(account.getAccount_name(),account.getAccount_password(),grantedAuthorities);
        /**
         * 创建UserDetails实现类对象User,将认证信息传给User对象进行认证
         * 参数1:要认证用户的用户名
         * 参数2:要认证用户的密码
         * 参数3:账户是否可以
         * 参数4:账户是否已经过期
         * 参数5:凭证是否已经过期
         * 参数6:账户是否已经被锁定
         * 参数7:要认证用户所拥有的权限集合
         */

        User userAuth = new User(
                account.getAccount_name(),
                account.getAccount_password(),
                account.getAccount_status()==0?true:account.getAccount_status()==-1?false:true,
                true,true,
                account.getAccount_status()==0?true:account.getAccount_status()==1?false:true,
                grantedAuthorities
        );

        return userAuth;
    }

    /**
     * 通过传入的角色获取存储用户角色权限集合
     * @param roles 角色集合
     * @return
     */
    public List<GrantedAuthority> getGrantedAuthorities(List<Role> roles){

        //创建一个用于存储用户认证权限的集合
        List<GrantedAuthority>  grantedAuthorities = new ArrayList<>();

        //遍历角色
        for (Role role : roles) {
            grantedAuthorities.add(new SimpleGrantedAuthority(role.getRole_name()));
        }

        return grantedAuthorities;
    }
}

登陆成功后,SpringScurity会将User认证对象中的信息存入到session中,我们可以通过获取一些对我们有用的信息进行处理。

我们在登陆成功的处理器中,获取一下登陆成功后session中所有的key,发现是SPRING_SECURITY_CONTEXT

我们再看一下这个key对应的值是什么?

org.springframework.security.core.context.SecurityContextImpl@f684df11: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@f684df11: Principal: org.springframework.security.core.userdetails.User@586034f: Username: admin; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_市场专员,ROLE_教学总监,ROLE_校长,ROLE_讲师; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@166c8: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 1F031DB88520531968829B142CF7A4D5; Granted Authorities: ROLE_市场专员, ROLE_教学总监, ROLE_校长, ROLE_讲师

我们发现存有一个User对象,其中有认证通过的用户信息。

三、登陆成功后,将需要的当前账户信息存入到session中

1.新建当前用户类,存储之后生成权限菜单所需要的信息

package com.jiazhong.office.commons;

import java.util.List;

/**
 * @ClassName: CurAccount 当前用户类
 * @Description: TODO 存储当前登录用户的信息
 * @Author: JiaShiXi
 * @Date: 2021/2/25 14:05
 * @Version: 1.0
 **/

public class CurAccount {
    private String account_name;
    private List<String> roleNames;

    public String getAccount_name() {
        return account_name;
    }

    public void setAccount_name(String account_name) {
        this.account_name = account_name;
    }

    public List<String> getRoleNames() {
        return roleNames;
    }

    public void setRoleNames(List<String> roleNames) {
        this.roleNames = roleNames;
    }

    @Override
    public String toString() {
        return "CurAccount{" +
                "account_name='" + account_name + '\'' +
                ", roleNames=" + roleNames +
                '}';
    }
}

2.新建常量类,存储项目中所用到的常量

package com.jiazhong.office.commons;

/**
 * @ClassName: Constant 常量类
 * @Description: TODO
 * @Author: JiaShiXi
 * @Date: 2021/2/25 14:08
 * @Version: 1.0
 **/

public class Constant {
    /**
     * session中存储的当前登陆的用户
     */
    public static final String SESSION_CUR_ACCOUNT = "SESSION_CUR_ACCOUNT";
}

3.在登陆成功的处理器中,获得session中的认证信息,封装到CurAccount中,并将存入CurAccount对象到session中

/**
     * 登陆成功后的操作
     * @return
     */
    @GetMapping("/result/loginSuccess")
    public Result loginSuccess(HttpSession session) {

        /**
         * 获得认证信息,封装到CurAccount中,并存入到session中
         */
        //获取当前的认证用户
        User user = (User) session.getAttribute("SPRING_SECURITY_CONTEXT");

        //将当前登录者的信息封装到当前登录者类中
        CurAccount curAccount = new CurAccount();
        curAccount.setAccount_name(user.getUsername());

        List<String> roleNames = new ArrayList<>();
        for (GrantedAuthority authority : user.getAuthorities()) {
            roleNames.add(authority.getAuthority());
        }

        curAccount.setRoleNames(roleNames);

        //将当前用户存入session中
        session.setAttribute(Constant.SESSION_CUR_ACCOUNT,curAccount);

        return Result.success("登陆成功");
    }

四、权限菜单的静态实现

在这里插入图片描述

<router-view />的作用是显示当前视图的根路由,加上该路由视图标签后,路由才会生效。

实现方法:

1.编写welcome.vue欢迎视图,并将其设置为main视图的根路由,访问main视图时,直接显示welcome.vue视图。

welcome.vue

<template>
    <div class="container-welcome">
        <h1>欢迎进入加中实训-云办公平台</h1>
    </div>
</template>

<style scoped>
    .container-welcome{
        display: flex;
        justify-content: center;
    }
</style>

index.js中配置路由

//配置main路由
    path:"/main/main",
    name:"Main",
    component:Main,
    /**配置main路由的子路由 */
    children:[
      {
        path:"/",//配置子路由中的根路由
        name:"Welcome",
        component:Welcome
      }
    ]

2.编写角色管理视图(role.vue)、用户管理视图(user.vue),并进行路由配置

<template>
    <div class="container-role">
        <h1>角色管理</h1>
    </div>
</template>

<style scoped>
    .container-welcome{
        display: flex;
        justify-content: center;
    }
</style>
<template>
    <div class="container-user">
        <h1>用户管理</h1>
    </div>
</template>

<style scoped>
    .container-welcome{
        display: flex;
        justify-content: center;
    }
</style>

在这里插入图片描述

3.修改main视图,当单击"用户管理"、“角色管理"时,分别跳转到"用户视图"和"角色视图”。

这里需要用到element ui 中菜单项的一个事件:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.效果:

刚进入:

在这里插入图片描述

点击用户管理菜单项:

在这里插入图片描述

单击角色管理菜单项:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
本课程是一门具有很强实践性质的“项目实战”课程,即“企业中台系统实战”,其中主要包含三大块核心内容,如下图所示(右键可以在新标签页中打开图片放大查看): 即主要包含以下三大块内容: ① 企业内部应用系统菜单资源和操作权限的统一管理; ② 分布式应用系统通信时的统一授权,即基于AccessToken的授权与认证; ③ 分布式服务/系统通信时的两大方式(基于dubbo rpc协议和基于http协议的restful api实战)。   值得一提的是,这套中台系统由于讲解了如何统一管理企业内部各大应用系统的“菜单资源列表”、“操作权限”,故而本门课程的“代码实战”是建立在之前debug录制的“企业权限管理平台”这套课程的基础之上的,故而在这里debug建议没有项目开发基础的小伙伴可以先去学习我的那套“企业权限管理平台”的实战课程,之后再来学习我的这套中台系统的实战才不会很吃力(课程链接:)   本课程的课程大纲如下图所示(右键可以在新标签页中打开图片放大查看):   除此之外,这套“中台系统”由于统一管理了企业内部各大应用系统的“菜单资源和操作权限”以及“应用系统之间通信时的统一授权”,故而难免需要涉及到“中台系统”与“中台子系统”、“中台子系统”与“中台子系统”之间的通信(即分布式服务之间的通信),在这里我们是采用“dubbo + zookeeper”的方式加以落地实现的,详情如下图所示(右键可以在新标签页中打开图片放大查看):   而众所周知,作为一款知名以及相当流行的分布式服务调度中间件,dubbo现如今已经晋升为Apache顶级的开源项目,未来也仍将成为“分布式系统”开发实战的一大利器,如下图所示为dubbo底层核心系统架构图(右键可以在新标签页中打开图片放大查看): 而在这门“中台系统实战”的课程中,我们也将始终贯彻、落地dubbo的这一核心系统架构图,即如何将中台系统开发的服务注册/发布到注册中心zookeeper,中台子系统如何订阅/消费/调度中台系统发布在zookeeper的接口服务,中台子系统在走http协议调度通信时dubbo如何进行拦截、基于token认证接口的调用者等等,这些内容我们在课程中将一一得到代码层面的实战落地!   下图为本课程中涉及到的分布式系统/服务之间 采用“http协议restfulapi”方式通信时的Token授权、认证的流程图(右键可以在新标签页中打开图片放大查看): 而不夸张地说,基于AccessToken的授权、认证方式在现如今微服务、分布式时代系统与系统在通信期间最为常用的“授权方式”了,可想而知,掌握其中的流程思想是多么的重要!   以下为本门课程的部分截图(右键可以在新标签页中打开图片放大查看):     核心技术列表: 值得一提的是,由于本门课程是一门真正介绍“中台思想”以及将“中台思想”和“分布式系统开发实战”相结合落地的课程,故而在学完本门课程之后,可以掌握到的核心技术自然是相当多的。主要由SpringBoot2.0、SpringMVC、Mybatis、Dubbo、ZooKeeper、Redis、OkHttp3、Guava-Retrying重试机制、JWT(Json Web Token)、Shiro、分布式集群session共享、Lombok、StreamAPI、Dubbo-Filter以及ServiceBean等等。如下图所示(右键可以在新标签页中打开图片放大查看):

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jackson Xi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值