天天看点

微人事学习笔记(持续更新)登录页面服务端登录接口制作前后端接口对接Home页面制作前后端分离权限管理思路探讨权限管理:后端接口设计基础信息设置页面

登录页面

不同的路径,在显示不同的东西。不同的router路径在router/index.js配置,配置路径还有对应的页面(vue)

const routes = [
  {
    path: '/',
    name: 'Login',
    component: Login
  }
]
           

服务端登录接口制作

总体步骤:

1、逆向工程,创建model包和mapper包

2、Hr实体类,实现

UserDetails

接口,并重写七个方法

3、创建HrService,根据用户名,通过HrMapper获取hr对象。并返回该对象

4、创建

SecurityConfig

配置类,继承

WebSecurityConfiguerAdapter

类;

配置密码加密;

重写

configure(AuthenticationManagerBuilder auth)

方法,并将hrService传入

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
	auth.userDetailsService(hrService);
}
           

6、写一个helloController来测试一下

7、测试成功,说明,Spring Security已经和数据库连接上了

8、重写

configure(HttpSecurity http)

方法,

写登录成功时的回调,登录失败时的回调,登出的回调

protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated() // 剩余所有请求都需要登录才能访问
            .and()
            .formLogin() // 表单登录
                .usernameParameter("username") // 携带参数 username的名称
                .passwordParameter("password") // 携带参数 passowrd的名称
                .loginProcessingUrl("/doLogin") // 如果使用PostMan,通过访问这个路径来登录
                .loginPage("/login")
                .successHandler(new AuthenticationSuccessHandler() { // 登录成功后的操作
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
                        resp.setContentType("application/json;charset=utf-8");
                        PrintWriter out = resp.getWriter();
                        // authentication 表示登录成功的用户信息
                        Hr hr = (Hr) authentication.getPrincipal();
                        // 返回RespBean对象
                        RespBean ok = RespBean.ok("登录成功", hr);
                        // 输出成字符串
                        String s = new ObjectMapper().writeValueAsString(ok);
                        out.write(s);
                        out.flush();
                        out.close();
                    }
                })
                .failureHandler(new AuthenticationFailureHandler() { // 登录失败的操作
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp,
                                                        AuthenticationException exception) throws IOException, ServletException {
                        resp.setContentType("application/json;charset=utf-8");
                        PrintWriter out = resp.getWriter();
                        RespBean respBean = RespBean.error("登录失败");
                        if(exception instanceof LockedException){
                            respBean.setMsg("账户被锁定,请联系管理员");
                        }else if(exception instanceof CredentialsExpiredException){
                            respBean.setMsg("密码过期");
                        }else if(exception instanceof AccountExpiredException){
                            respBean.setMsg("账户过期,请联系管理员");
                        }else if(exception instanceof DisabledException){
                            respBean.setMsg("账户被禁用,请联系管理员");
                        }else if(exception instanceof BadCredentialsException){
                            respBean.setMsg("用户名或者密码错误,请联系管理员");
                        }

                        out.write(new ObjectMapper().writeValueAsString(respBean));
                        out.flush();
                        out.close();
                    }
                })
                .permitAll() //
            .and()
                .logout()
                .logoutSuccessHandler(new LogoutSuccessHandler() { // 登出的操作
                    @Override
                    public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {

                    }
                })
                .permitAll()
            .and()
                .csrf().disable();
    }
           

9、使用PostMan访问

http://localhost:8080/doLogin

测试一下,

1、在hr类实现

UserDetails

接口,实现方法

2、创建HrService,并实现

UserDetailsService

接口,实现

loadUserByUsername

方法

2.1、查询hr对象,使用MyBatis查询。如果等于null,抛出异常

UsernameNotFoundException

2.2、查询

3、配置security配置类,继承

WebSecurityConfiguerAdapter

3.1、注入hrService

@Autowired
HrService hrService;
           

3.2、配置Bean,密码加密的bean

@Bean
PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}
           

3.3、实现

configure

方法

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(hrService);
}
           

3.4、然后测试下

写一个helloController,get方式请求,返回一个hello就好

如果登录成功,说明已经介入到数据库了

3.5、因为是前后端分离,所以需要配置使用JSON的方式登录

登陆成功:返回一个登录成功的JSON

登录失败:返回一个登录失败的JSON

定义一个统一的返回Bean:RespBean,看源码里边有

实现

configure(HttpSecurity http)

接口:

.permitAll() 表示登录相关的页面/接口不要被拦截。

登录成功的回调:

.successHandler

authentication:登录成功的用户信息

登录成功返回的是一个RespBean对象

.successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
                        resp.setContentType("application/json;charset=utf-8");
                        PrintWriter out = resp.getWriter();
                        Hr hr = (Hr) authentication.getPrincipal();
                        RespBean ok = RespBean.ok("登录成功", hr);
                        String s = new ObjectMapper().writeValueAsString(ok);
                        out.write(s);
                        out.flush();
                        out.close();
                    }
                })
           

登录成功后,不显示密码

hr.setPassword(null)

登录失败的回调:

.failureHandler

.failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException e) throws IOException, ServletException {
                        resp.setContentType("application/json;charset=utf-8");
                        PrintWriter out = resp.getWriter();
                        RespBean error = RespBean.error("登录失败");
                        if (e instanceof LockedException) {
                            error.setMsg("账户被锁定,请联系管理员");
                        } else if (e instanceof CredentialsExpiredException) {
                            error.setMsg("密码过期,请联系管理员");
                        } else if (e instanceof AccountExpiredException) {
                            error.setMsg("账户过期,请联系管理员");
                        }else if (e instanceof DisabledException) {
                            error.setMsg("账户被禁用,请联系管理员");
                        }else if(e instanceof BadCredentialsException){
                            error.setMsg("用户名或者密码输入错误,请联系管理员");
                        }
                        String s = new ObjectMapper().writeValueAsString(error);
                        out.write(s);
                        out.flush();
                        out.close();
                    }
                })
           

定义一个

LoginController

来处理登录页的问题

@RestController
public class LoginController {

    @GetMapping("/login")
    public RespBean login(){
        return RespBean.error("尚未登录,请登录");
    }
}
           

登出的回调:

.logoutSuccessHandler

authentication:表示需要注销的用户

直接返回一个RespBean对象

前后端接口对接

安装axios,

npm install axios

1、封装网络请求,创建utils包,再创建api.js。

  • 在里边写一个响应拦截器。

    success.status

    这是http的响应码,

    success.data.status

    这是我们返回的JSON的响应码
import axios from 'axios'
import {Message} from 'element-ui'

/*响应的拦截器*/
axios.interceptors.response.use(success=>{
    if(success.status && success.status ==200 && success.data.status==500){
        Message.error({message:success.data.msg})
        return;
    }
    return success.data;

},error => {
    if(error.response.status == 504 ||error.response.status == 404 ){
        Message.error({message:'没找到服务器o(╯□╰)o'})
    }else if(error.response.status == 403 ){
        Message.error({message: '权限不足,请联系管理员'})
    }else if(error.response.status == 401 ){
        Message.error({message: '没有登录,请登录'})
    }else{
        if(error.response.data.msg){
            Message.error({message:error.response.data.nsg})
        }else{
            Message.error({message: '未知错误!'})
        }
    }

    return;
})
           
  • 再写一个POST请求的封装,(新增 封装多个请求
let base = '';

// 传递key value的请求
export const postKeyValueRequest=(url,params)=>{
    return axios({
        method:'post',
        url:`${base}${url}`,
        data:params,
        transformRequest:[function(data){
            let ret = '';
            for(let i in data){
                ret +=encodeURIComponent(i) +'=' + encodeURIComponent(data[i])+'&'
            }
            console.log(ret);
            return ret;
        }],
        headers:{
            'Content-Type':'application/x-www-form-urlencoded'
        }
    });
}

// 传递JSON的请求
export const postRequest=(url,params)=>{
    return axios({
        method:'post',
        url:`${base}${url}`,
        data:params
    })
}

export const putRequest=(url,params)=>{
    return axios({
        method:'put',
        url:`${base}${url}`,
        data:params
    })
}

export const getRequest=(url,params)=>{
    return axios({
        method:'get',
        url:`${base}${url}`,
        data:params
    })
}

export const deleteRequest=(url,params)=>{
    return axios({
        method:'delete',
        url:`${base}${url}`,
        data:params
    })
}
           

将封装的请求,做成vue插件

在main.js把封装的请求都导入进来
import {postRequest} from "./utils/api";
import {postKeyValueRequest} from "./utils/api";
import {putRequest} from "./utils/api";
import {deleteRequest} from "./utils/api";
import {getRequest} from "./utils/api";

Vue.prototype.postRequest = postRequest;
Vue.prototype.postKeyValueRequest = postKeyValueRequest;
Vue.prototype.putRequest = putRequest;
Vue.prototype.deleteRequest = deleteRequest;
Vue.prototype.getRequest = getRequest;

使用:
this.封装的请求.
如:this.postRequest()
           
  • 使用封装的请求
    • 1、先导入:

      import {postKeyValueRequest} from "../utils/api"

    • 2、使用:
    • 另外一种使用方法:

      this.postRequest()

      前提是已经做成了一个vue插件
postKeyValueRequest('/doLogin', this.loginForm).then(resp=>{
	if(resp) {
		alert(JSON.stringify(resp))
	}
})
           

​ 通过

if(resp)

判断请求成功还是失败,失败不用管,因为在拦截器已经处理过了

  • 跨域问题处理:配置 nodejs 请求转发代理vue.config.js
let proxyObj = {};
proxyObj['/']={
    ws:false,
    target:'http://localhost:8081', // 把拦截的请求转发到8081端口区
    changeOrigin: true,
    pathRewrite:{
        '^/':''
    }
} 

module.exports={
    devServer:{
        host:'localhost',
        port:8080,
        proxy:proxyObj
    }
}
           

2、保存请求回来的数据到

sessionStorage

3、保存后再进行页面跳转,跳转到

Home.vue

页面

3.1、创建

Home.vue

页面

3.2、在

Router.js

中引入,并设置

3.3、跳转

this.$router.replace('/home')

postKeyValueRequest('/doLogin', this.loginForm).then(resp=>{
	if(resp) {
		window.sessionStorage.setItem("user", JSON.stringify(resp.obj));
		this.$router.replace('/home')
	}
})
           

Home页面制作

sessionStorage

读取用户信息

注销登录要把

sessionStorage

的信息清空

api.js加上一个登录成功的提示

if(success.data.msg) {
	Message.success({message:success.data.msg})
}
           
左边导航菜单制作

1、在右边显示窗口加一个

2、在router包下index.js添加

{
        path: '/home',
        name: '导航一',
        component: Home,
        children:[
            {
                path: '/test1', // 要跳转的页面,这里为vue
                name: '选项1',
                component: Test1
            }, {
                path: '/test2',
                name: '选项2',
                component: Test2
            }
        ]
    }
           

3、统一Home.vue和index.js的选项页面

渲染index.js的routes到Home.vue中,添加hidden给不需要渲染的routes,用来区分。

<el-menu  router>
                        <el-submenu index="1" v-for="(item,index) in this.$router.options.routes" v-if="!item.hidden" :key="index">
                            <template slot="title">
                                <i class="el-icon-location"></i>
                                <span>{{item.name}}</span>
                            </template>

                            <el-menu-item :index="child.path" v-for="(child,indexj) in item.children " :key="indexj">
                                {{child.name}}
                            </el-menu-item>

                        </el-submenu>

</el-menu>
           

4、通过数据库动态修改左边导航菜单

  • menu表里存有导航菜单,分有一级菜单,二级菜单。enabled表示菜单是否启用,requireAuth表示需要登录才能访问。
  • 根据用户id获取角色id,根据角色id获取menu id,再通过menu id获取用户可以操作的菜单。

目的:通过服务端根据用户id返回一个menu菜单。

1、修改menu实体类,改成驼峰法(看个人)

2、将额外的字段放到一个meta类里边,

这里将keepAlive,requireAuth定义成meta类的成员变量

在menu实体类增加一个meta成员变量,

在menu实体类增加一个children成员变量,List

类型,

在MenuMapper的resultMap修改:

<association property="meta" javaType="org.javaboy.vhr.model.Meta">
      <result column="keepAlive" property="keepAlive" jdbcType="BIT" />
      <result column="requireAuth" property="requireAuth" jdbcType="BIT" />
</association>
           

3、写一个controller查询需要的数据,系统配置的controller(SystemConfigController),创建MenuService。

通过系统保存的用户对象的id来查询,

(Hr)SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getId()

mapper进行查询:

sql语句:

select 
	distinct m1.*,m2.id as id2,m2.component as component2,
m2.enabled as enabled2,
m2.iconCls as iconCls2,m2.keepAlive as keepAlive2,m2.name as name2,
m2.parentId as parentId2,m2.requireAuth as requireAuth2,m2.path as path2 
from
	hr_role hrr,
	menu_role mr,
	menu m2,
	menu m1
where
	hrr.hrid=10
and hrr.rid=mr.rid
and m2.id = mr.mid
and m1.id = m2.parentId
and m1.enabled=true

// 目的:查询该用户所拥有的菜单信息
// 步骤:
1、查询用户为10的角色id
2、根据角色id查询该角色拥有的菜单id
3、根据菜单id查询具体的菜单信息
4、根据菜单id链接菜单的父类菜单信息
5、给子菜单的字段取个别名
           

重新定义一个resultMap:

<resultMap id="Menus2" type="org.javaboy.vhr.model.Menu" extends="BaseResultMap">
    <collection property="children" ofType="org.javaboy.vhr.model.Menu">
      <id column="id2" property="id" jdbcType="INTEGER" />
      <result column="url2" property="url" jdbcType="VARCHAR" />
      <result column="path2" property="path" jdbcType="VARCHAR" />
      <result column="component2" property="component" jdbcType="VARCHAR" />
      <result column="name2" property="name" jdbcType="VARCHAR" />
      <result column="iconCls2" property="iconCls" jdbcType="VARCHAR" />
      <result column="parentId2" property="parentId" jdbcType="INTEGER" />
      <result column="enabled2" property="enabled" jdbcType="BIT" />
      <association property="meta" javaType="org.javaboy.vhr.model.Meta">
        <result column="keepAlive2" property="keepAlive" jdbcType="BIT" />
        <result column="requireAuth2" property="requireAuth" jdbcType="BIT" />
      </association>
    </collection>
  </resultMap>
           

5、菜单项数据加载成功之后,在前端有几个可以存放的地方:

sessionStorage

localStorage

vuex

需要把加载下来的菜单项数据,需要放在一个公共的地方,让大家都能访问

vuex:状态管理。把数据放在一个公共的地方。可以用于数据共享,互相调用。

vuex的安装:

npm install vuex

vuex的用法:

  • 创建一个

    store

    包,创建

    index.js

    文件
  • main.js

    引入。 在new Vue里加入
import Vue from 'vue'
import Vuex from 'vuex'

Vue.user(Vuex)

export default new Vuex.Store({
    state:{
        routes:[] // 菜单项都放在这个数据里
    },
    mutations:{
        initRoutes(state,data){ // 这里写怎么放
            state.routes = data;
        }
    },
    actions:{

    }
})

// 引入
import store from './store'
new Vue({
    // 加上一个
    store,
})
           

6、写一个专门的工具类,功能:1、从服务端请求数据。2、把服务端返回的字符串转成前端的对象;3、把服务端返回的数据放到

router.js

中去

在utiles包中创建,

menus.js

在views包中创建组件的vue:有五个包:emp、per、sal、sta、sys。也拷贝一份到components

emp:EmpBasic.vue(基本资料)、EmpAdv.vue(高级资料)
per:PerEmp(员工资料)、PerEc(员工奖惩)、PerTrain(员工培训)、PerSalary(员工调薪)、PerMv(员工调动)
sal:SalSob(工资账套管理)、SalSobCfg(员工账套设置)、SalTable(工资表管理)、SalMonth(月末处理)、SalSearch(工资表查询)
sta:StaAll(综合信息统计)、StaScore(员工积分统计)、StaPers(人事信息统计)、StaRecord(人事记录统计)
sys:SysBasic(基础信息设置)、SysCfg(系统管理)、SysLog(操作日志管理)、SysHr(操作员管理)、SysData(备份恢复数据库)、SysInit(初始化数据库)
           
import {getRequest} from "../../utils/api";


export const initMenu=(router,store) =>{ // 要存到router,要保存到store
    if(store.state.routes.length > 0){
        // 说明有菜单数据,直接返回
        return;
    }
    getRequest("/system/config/menu").then(data =>{
        if(data){
            let fmtRoutes = formatRoutes(data);
            router.addRoutes(fmtRoutes);
            store.commit('initRoutes', fmtRoutes); // 调用initRoutes这个方法
        }
    })
}

// 把一些字符串字段变成前端对象
export const formatRoutes=(routes)=>{
    let fmRoutes = [];
    routes.forEach(router =>{
        let{
            path,
            component,
            name,
            meta,
            iconCls,
            children
        } = router // router.path, router.name, router.component....

        if(children && children instanceof Array){
            // 说明是一级菜单
            // 递归调用
            children = formatRoutes(children);
        }

        let fmRouter={
            path:path,
            name:name,
            iconCls:iconCls,
            meta:meta,
            children:children,
            component(resolve){ // 主要是处理这个component,componen就是返回的字符串: component:"。。是这个。。"
                // 动态导入(用的时候再导入这个文件,类似于import...),导入这个vue。
                if(component.startsWith("Home")){
                    require(['../views/' + component+'.vue'],resolve);
                }else if (component.startsWith("Emp")){
                    require(['../views/emp/' + component+'.vue'],resolve);
                }else if(component.startsWith("Per")) {
                    require(['../views/per/' + component+'.vue'],resolve);
                }else if(component.startsWith("Sal")) {
                    require(['../views/sal/' + component+'.vue'],resolve);
                }else if(component.startsWith("Sta")) {
                    require(['../views/sta/' + component+'.vue'],resolve);
                }else if(component.startsWith("Sys")) {
                    require(['../views/sys/' + component+'.vue'],resolve);
                }
            }
        }
        fmRoutes.push(fmRouter);
    })
    return fmRoutes;
}
           

7、左边导航栏菜单加载

通过路由导航守卫调用

initMenu()

方法来加载菜单项

路由导航守卫 :路由页面在跳转过程中,可以对页面的跳转进行监听,可以过滤。

https://router.vuejs.org/zh/guide/advanced/navigation-guards.html

在main.js加载路由导航守卫

router.beforeEach(to, from, next) => {
	// from:从哪来
	// to:去哪里
	if (to.path == '/') { // 如果要去的页面是登录页,直接放行
		next(); 
	}else {
		// 调用initMenu方法加载菜单项 ,记得导入 import {initMenu} from "@/store/menus"
		initMenu(router, store);
		next();
	}
}
           

替换菜单项,把菜单项换成store里存的数据。使用computed

在Home.vue中添加

computed: {
	routes(){
		return this.$store.state.routes;
	}
}
然后导航页的数据源代码换成:routes,再加一个unique-opened..看别人的那个代码

注销登录时,要清空store里的数据
this.$store.commit('initRoutes',[])
           

安装图标库:看网页

完善首页:看网页

前后端分离权限管理思路探讨

目的:前端做菜单显示只是为了提高用户体验,而不是进行权限控制

权限:后端会提供很多接口,每个接口都需要用户或者角色才能访问。没有权限就访问不了接口。

后端处理的权限才是安全的,前端处理的不是安全的。

权限管理:后端接口设计

1、前端先发起一个http请求,拿到请求后,先分析地址和menu表的url字段哪一个是匹配的。

2、然后去menu_role去查看,哪些角色能访问这个资源。

3、查看当前登录的用户是否具备所需要的角色,如果具备那就没问题,不具备就是越权访问。

1、写一个类,来实现:通过请求地址来获取请求地址所需要的角色

2、写一个类,来判断:当前用户是否具备有上边类返回结果所需要的角色

3、在Security配置类中,设置这两个类

4、给登录用户设置角色信息

接口设计

1、定义一个Fileter实现FilterInvocationSecurityMetadataSource接口(这个类的功能就是启动权限访问)(根据用户传来的请求地址,分析出请求需要的角色)

2、主要写

getAttributes

这个方法

3、Menu类加一个

List<Role> Roles

MenuService写一个

getAllMenusWithRole

方法。Mapper写一个sql:

在定义一个ResultMap

SELECT m.*,r.id as rid,r.name as rname,r.nameZh as rnameZh
FROM menu m,menu_role mr, role r
WHERE m.id=mr.mid and mr.rid=r.id
ORDER BY m.id
           
public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException
//
Collection<ConfigAttribute>:当前请求需要的角色
           

第一步:通过分析当前请求地址,需要哪些角色才能访问

// 最终目的:通过分析当前请求地址,需要哪些角色才能访问
@Override
    public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {

        String requestUrl = ((FilterInvocation) o).getRequestUrl(); // 当前请求的地址
        List<Menu> menus = menuService.getAllMenusWithRole(); // 获取所有的菜单所需要的角色。需要开缓存,不然每次都会去查数据库 
        // 遍历menus比较当前请求路径
        // antPathMatcher需要new
        for (Menu menu : menus) {
            if(antPathMatcher.match(menu.getUrl(),requestUrl)){
                // 获取当前资源需要的角色
                List<Role> roles = menu.getRoles();
                String[] str = new String[roles.size()];
                for (int i = 0; i < roles.size(); i++) {
                    str[i] = roles.get(i).getName();
                }
                return SecurityConfig.createList(str);
            }
        }

        // 表示没有匹配上的,都是登录后访问
        return SecurityConfig.createList("ROLE_LOGIN");
}
           

第二步:分析当前用户是否具备有所访问资源的角色

写一个类,实现

AccessDecisionManager

接口,用来判断当前用户是否具备所访问资源的角色,如果具有就过。

主要重写:

public void decide(Authentication authentication, Object o,
                       Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException
           
// authentication:登录成功的用户信息。Collection<ConfigAttribute> collection:是上边Fileter的返回值,就是menu需要的角色信息
@Override
    public void decide(Authentication authentication, Object o,
                       Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException {
        for (ConfigAttribute configAttribute : collection) {
            String needRole = configAttribute.getAttribute(); // 需要的角色
            // 判断有没有登录。如果当前用户是匿名实例的话,就说明没登录
            if("ROLE_LOGIN".equals(needRole)){
                if(authentication instanceof AnonymousAuthenticationToken){
                    throw new AccessDeniedException("尚未登录,请登录");
                }else{
                    return;
                }
            }

            // 获取当前登录用户的角色
            Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
			// 如果资源需要的角色有多个,只需要判断当前用户的角色有一个在里边就可以
            for (GrantedAuthority authority : authorities) {
                if(authority.getAuthority().equals(needRole)){
                    return;
                }
            }
        }

        throw new AccessDeniedException("权限不足,请联系管理员");
}
           

第三步:在

SecurityConfig

引进这两个类就可以了

.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O object) {
                        object.setAccessDecisionManager(customUrlDecisionManager);
                        object.setSecurityMetadataSource(customFilterInvocationSecurityMetadataSource);
                        return object;
                    }
})
           

第四步:给用户给角色

Hr类添加 List roles 属性

这个操作就是给用户赋角色的值

@Override
@JsonIgnore
public Collection<? extends GrantedAuthority> getAuthorities() {
    List<SimpleGrantedAuthority> authorities = new ArrayList<>(roles.size());
    for (Role role : roles) {
        authorities.add(new SimpleGrantedAuthority(role.getName()));
    }
    return authorities;
}
           

在登录成功后,获取登录用户的角色,并给Hr的roles赋值,在HrService里:

添加:
hr.setRoles(hrMapper.getHrRolesById(hr.getId()));
           

写sql:根据用户id查询用户用拥有的角色

第四步:测试

如果访问

/login

不用经过

Spring Security

SecurityConfig

加上

@Override
public void configure(WebSecurity web) throws Exception {
	web.ignoring().antMatchers("/login");
}
           

完善权限管理:看网页!

基础信息设置页面

前端:复制别人的

vue的组件化开发,由小的页面(组件)拼接成一个完整的页面(组件)

1、在components包下创建sys包创建basic包,创建5个组件:DepMana、PosMana、JobLevelMana、EcMana、PermissMana

2、在SysBasic.vue引入这五个组件

import DepMana from '../../components/sys.......'
自己写吧。。。。
并注册组件
components:{
	// 'DepMana':DepMana,前边跟后边一样的可以简写成下边这样。
	DepMana
}

在<template></template>内写<DepMana></DepMana>
如:
<el-tab-pane label="部门管理" name="a"><DepMana></DepMana></el-tab-pane>