天天看點

微人事學習筆記(持續更新)登入頁面服務端登入接口制作前後端接口對接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>