day20_权限控制
1filter简介

2过滤器实例
1过滤器通过请求地址 进入调用链
package com.javasm.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* @className: MyFilter
* @author: gfs
* @date: 2025/10/28 9:55
* @version: 0.1
* @since: jdk17
* @description:
*/
@WebFilter("/listArea")
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//相当于servlet中的service 请求地址匹配到会自动执行
System.out.println("/filter1 going......");
//调用链继续向后执行
filterChain.doFilter(servletRequest,servletResponse);
}
}
2多层过滤器配置
/* * 如果使用了多层过滤 * 自动形成过滤器链 规则跟配置方式有关 * 1注解方式 根据包名 类名顺序排列 调用顺序 (特例 特殊包名类会倒着加载) * 测试一下 包名+类名是否符合需要的顺序 * * 2配置文件方式 从上到下加载 写在上边的先运行 下边的后运行 * * */
package com.javasm.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* @className: MyFilter
* @author: gfs
* @date: 2025/10/28 9:55
* @version: 0.1
* @since: jdk17
* @description:
*/
@WebFilter("/listArea")
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//相当于servlet中的service 请求地址匹配到会自动执行
System.out.println("/filter1 going......");
//调用链继续向后执行
filterChain.doFilter(servletRequest,servletResponse);
/*
* 如果使用了多层过滤
* 自动形成过滤器链 规则跟配置方式有关
* 1注解方式 根据包名 类名顺序排列 调用顺序 (特例 特殊包名类会倒着加载)
* 测试一下 包名+类名是否符合需要的顺序
*
* 2配置文件方式 从上到下加载 写在上边的先运行 下边的后运行
*
* */
}
}
package com.javasm.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* @className: MyFilter
* @author: gfs
* @date: 2025/10/28 9:55
* @version: 0.1
* @since: jdk17
* @description:
*/
@WebFilter("/listArea")
public class MyFilter2 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//相当于servlet中的service 请求地址匹配到会自动执行
System.out.println("/filter2 going......");
//调用链继续向后执行
filterChain.doFilter(servletRequest,servletResponse);
}
}
3通过通配符* 扩大请求进入的范围
/* * 使用通配符 扩大请求进入范围 * 1精确匹配servlet * /user/* /menus/* 可以对两个模块同时生效 过滤器 /serv/* servlet /serv/user/* /serv/menus/* 只对一个模块生效 过滤器 /serv/user/* 2全局匹配servlet /* 所有请求都进入 根据请求路径 排除掉一些请求 不走过滤器的判断逻辑 * * * */
对某个servlet生效
package com.javasm.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* @className: MyFilter
* @author: gfs
* @date: 2025/10/28 9:55
* @version: 0.1
* @since: jdk17
* @description:
*/
@WebFilter("/serv/listArea/*")
public class MyFilter2 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//相当于servlet中的service 请求地址匹配到会自动执行
System.out.println("/filter2 going......");
//调用链继续向后执行
filterChain.doFilter(servletRequest,servletResponse);
}
}
对多个servlet生效
package com.javasm.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* @className: MyFilter
* @author: gfs
* @date: 2025/10/28 9:55
* @version: 0.1
* @since: jdk17
* @description:
*/
@WebFilter("/serv/*")
public class MyFilter2 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//相当于servlet中的service 请求地址匹配到会自动执行
System.out.println("/filter2 going......");
//调用链继续向后执行
filterChain.doFilter(servletRequest,servletResponse);
}
}
对全局生效
package com.javasm.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* @className: MyFilter
* @author: gfs
* @date: 2025/10/28 9:55
* @version: 0.1
* @since: jdk17
* @description:
*/
@WebFilter("/*")
public class MyFilter2 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//相当于servlet中的service 请求地址匹配到会自动执行
System.out.println("/filter2 going......");
//调用链继续向后执行
filterChain.doFilter(servletRequest,servletResponse);
}
}
3项目中加入过滤器 做公共功能
1请求编码 跨域过滤器
package com.javasm.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @className: MyFilter1
* @author: gfs
* @date: 2025/10/28 10:39
* @version: 0.1
* @since: jdk17
* @description:
*/
@WebFilter("/*")
public class MyFilter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//把类型转为子接口类型 方便调用http相关的内容
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
//请求参数公共配置
servletRequest.setCharacterEncoding("utf-8");
//跨域配置
/* 允许跨域的主机地址*/
resp.setHeader("Access-Control-Allow-Origin", "http://localhost:5173");
/* 允许跨域的请求⽅法GET, POST, HEAD 等*/
resp.setHeader("Access-Control-Allow-Methods", "*");
/*重新预检验跨域的缓存时间*/
resp.setHeader("Access-Control-Max-Age", "3600");
/* 允许跨域的请求头 */
resp.setHeader("Access-Control-Allow-Headers", "*");
/* 是否携带cookie */
resp.setHeader("Access-Control-Allow-Credentials", "true");
//不要轻易设置
//resp.setContentType("application/json;charset=utf-8");
filterChain.doFilter(servletRequest,servletResponse);
}
}
2权限控制过滤器
登录访问控制过滤器
package com.javasm.filter;
import com.alibaba.fastjson.JSON;
import com.javasm.entity.AdminUser;
import com.javasm.entity.ReturnCode;
import com.javasm.entity.ReturnResult;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @className: MyFilter2
* @author: gfs
* @date: 2025/10/28 10:49
* @version: 0.1
* @since: jdk17
* @description:
*/
@WebFilter("/*")
public class MyFilter2 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//把类型转为子接口类型 方便调用http相关的内容
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
//做权限控制
//登录访问控制
HttpSession session = req.getSession();
AdminUser loginUser =(AdminUser) session.getAttribute("loginUser");
String requestURI = req.getRequestURI();
String servletPath = req.getServletPath();
System.out.println(requestURI);
System.out.println(servletPath);
//白名单 (特权)
if("/login".equals(servletPath)){
filterChain.doFilter(req,resp);
}else{
if(loginUser!=null){
//登录过 继续执行要访问的服务
filterChain.doFilter(req,resp);
}else{
ReturnResult returnResult = new ReturnResult(ReturnCode.NOT_LOGIN.getCode(),ReturnCode.NOT_LOGIN.getMsg());
//输出json数据
resp.setContentType("application/json;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.print(JSON.toJSONString(returnResult));
writer.close();
}
}
}
}
前端 需要根据后端数据做适配
axios中增加响应拦截器 如果接收到没有登录的响应码 跳转到登录页面
import axios from 'axios'
import router from '@/router'
//技术的二次封装
//可以有公共的请求url协议 地址 路径
//如果路径中给的是带协议的完整路径 优先走完整路径
axios.defaults.baseURL = 'http://localhost:8080/baseProj';
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
//跨域时发送cookie 为了使用session
axios.defaults.withCredentials = true
//无session模式 自己传请求头里 放票据信息 后端自己存缓存 自己判断
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
if(response.data.code == 10020){
router.push("/login")
return
}
return response;
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error);
});
//使用二次封装的get post请求
const myPost = (currentURL,params)=>{
// 发起一个post请求
return axios({
method: 'post',
url: currentURL,
data: params
});
}
const myGet = (currentURL,params)=>{
return axios({
method: 'get',
url: currentURL,
params: params
});
}
export {axios,myPost,myGet};
主页面中 检查是否有登录的标记 如果没有跳转到登录页面
top.vue
<script setup>
import { ref,onMounted } from 'vue'
import { User, Histogram, SwitchButton } from '@element-plus/icons-vue'
import router from '@/router'
import {axios,myPost,myGet} from '@/axios/myAxios.js'
import { ElMessage,ElMessageBox } from 'element-plus';
const username = ref('')
onMounted(()=>{
//从sessionStorage中获取登录用户
let loginUserStr = sessionStorage.getItem('loginUser')
//如果有值 转成json
if(loginUserStr){
//显示到登录的用户名中
let lignUser = JSON.parse(loginUserStr)
username.value = lignUser.username
}else{
//判断是否有登录标记 没哟 跳转到登录
router.push('/login')
}
})
const logout = async()=>{
//清除sessionStorage中的登录用户
sessionStorage.removeItem('loginUser')
//清后端数据
let resp = await myGet("/logout");
ElMessage.info(resp.data.msg)
//跳转到登录页面
router.push('/login')
}
</script>
<template>
<el-row justify="end">
<el-col style="font-size: 30px;color: gray;" :span="12">XXXX管理系统</el-col>
<el-col :span="8">
<el-button-group >
<el-button type="primary" color="#DDD" :icon="User" >{{username}}</el-button>
<el-button type="primary" color="#DDD" :icon="Histogram" />
<el-button type="primary" color="#CCC" :icon="SwitchButton" @click="logout" />
</el-button-group>
</el-col>
</el-row>
</template>
<style scoped></style>
3模块权限
动态菜单只能限制没有界面 但是不能限制直接访问接口 所以需要通过过滤器做限制
登录时 读取该用户可访问的url列表 存入缓存
package com.javasm.controller;
import com.alibaba.fastjson.JSON;
import com.javasm.entity.AdminMenu;
import com.javasm.entity.AdminUser;
import com.javasm.entity.ReturnCode;
import com.javasm.entity.ReturnResult;
import com.javasm.service.LoginService;
import com.javasm.service.impl.LoginServiceImpl;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
/**
* @className: LoginServlet
* @author: gfs
* @date: 2025/10/23 14:43
* @version: 0.1
* @since: jdk17
* @description:
*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1接收参数 转格式 封装对象
String username = req.getParameter("username");
String password = req.getParameter("password");
//2调用service
LoginService loginService = new LoginServiceImpl();
//开始检查信息是否符合要求
AdminUser loginUser = loginService.getUserByName(username);
//3根据结果 反馈数据
ReturnResult rr = new ReturnResult();
if(loginUser!=null){
if(loginUser.getIsvalid() == 1){
if(loginUser.getPassword().equals(password)){
//登录成功 .....
//1.把登录用户存入session 为后续流程缓存用户数据
HttpSession session = req.getSession();
session.setAttribute("loginUser",loginUser);
//2.更新最后登录时间
loginService.updateLoginTime(loginUser.getUid());
//3.查询当前用户的菜单信息
List<AdminMenu> listMenuByUid = loginService.listMenuByUid(loginUser.getUid());
//4.查询当前用户可访问url列表 存入后端缓存
List<String> userUrl = loginService.listUrlByUid(loginUser.getUid());
session.setAttribute("userUrl",userUrl);
//5.返回操作成功信息
rr.setCode(ReturnCode.LOGIN_SUCCESS.getCode());
rr.setMsg(ReturnCode.LOGIN_SUCCESS.getMsg());
//如果有关联 通过对象关联体现数据关系
loginUser.setUserMenu(listMenuByUid);
//如果没关联 建自定义map存放不同类别的数据
// HashMap<String, Object> returnMap = new HashMap<>();
// returnMap.put("loginUser",loginUser);
// returnMap.put("userMenu",listMenuByUid);
// rr.setReturnData(returnMap);
rr.setReturnData(loginUser);
}else{
//密码不对
rr.setCode(ReturnCode.LOGIN_FAILED1.getCode());
rr.setMsg(ReturnCode.LOGIN_FAILED1.getMsg());
}
}else{
//用户已离职
rr.setCode(ReturnCode.LOGIN_FAILED2.getCode());
rr.setMsg(ReturnCode.LOGIN_FAILED2.getMsg());
}
}else{
//用户名找不到
rr.setCode(ReturnCode.LOGIN_FAILED1.getCode());
rr.setMsg(ReturnCode.LOGIN_FAILED1.getMsg());
}
//输出json数据
resp.setContentType("application/json;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.print(JSON.toJSONString(rr));
writer.close();
}
}

在过滤器中判断当次请求是否在可访问列表中
package com.javasm.filter;
import com.alibaba.fastjson.JSON;
import com.javasm.entity.ReturnCode;
import com.javasm.entity.ReturnResult;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
/**
* @className: MyFilter1
* @author: gfs
* @date: 2025/10/28 10:39
* @version: 0.1
* @since: jdk17
* @description:
*/
@WebFilter("/*")
public class MyFilter3 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//把类型转为子接口类型 方便调用http相关的内容
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
// 读取到 /users /menus
String servletPath = req.getServletPath();
HttpSession session = req.getSession();
List<String> userUrl =(List<String>) session.getAttribute("userUrl");
//配置白名单
//系统中不需要单独配置 默认每个用户都会有的功能
//上传头像 静态资源 html css js 图片 视频 声音
if("/login".equals(servletPath)||"/logout".equals(servletPath)||servletPath.endsWith(".png")||servletPath.endsWith(".jpg")||servletPath.endsWith(".gif")){
filterChain.doFilter(req,resp);
}else{
//查集合中是否有指定元素
if(userUrl.contains(servletPath)){
//有权限
filterChain.doFilter(req,resp);
}else{
//没权限
ReturnResult returnResult = new ReturnResult(ReturnCode.LOGIN_NO_POMISSION.getCode(),ReturnCode.LOGIN_NO_POMISSION.getMsg());
//输出json数据
resp.setContentType("application/json;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.print(JSON.toJSONString(returnResult));
writer.close();
}
}
}
}
注意:
不同功能的过滤器 白名单配置的逻辑是不同的 需要单独考虑
1699

被折叠的 条评论
为什么被折叠?



