基于传统Session的登录

news2024/11/20 19:30:22

前言:

本人的一些简历上要回答的点。所以再此整理。

亮点:

使用Filter过滤器进行未登录状态自动跳转到登录页面的拦截,实现统一的权限管理。

1 登陆功能

1.1实体类和结果类

前端页面

约定 res.data.code为1时是登录成功。

数据库的employee员工表:

员工表存储员工的用户名、密码、身份证等信息,用来后台页面登录。

这里password是加密后的数据,真实数据是123456

创建实体类Employee

@Data
 
//实体类实现Serializable接口,把对象转换为字节序列。序列化操作用于存储时,一般是对于NoSql数据库。
public class Employee implements Serializable {
//在反序列化的过程中,如果接收方为对象加载了一个类,如果该对象的serialVersionUID与对应持久化时的类不同,那么反序列化的过程中将会导致InvalidClassException异常。
    private static final long serialVersionUID = 1L;
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    private Long id;
 
    private String username;
 
    private String name;
 
    private String password;
 
    private String phone;
 
    private String sex;
 
    private String idNumber;
 
    private Integer status;
    @TableField(fill=FieldFill.INSERT)
    private LocalDateTime createTime;
    @TableField(fill =FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
//阿里巴巴的开发规范中推荐每个表都带有一个createTime 和一个 updateTime, 但是每次自己手动添加太麻烦了,可以配置MP让其自动添加,使用@TableField的fill注解。
    @TableField(fill = FieldFill.INSERT)
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    private Long createUser;
 
    @TableField(fill = FieldFill.INSERT_UPDATE)
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    private Long updateUser;
 
}

R结果类:
 

​​​​​​​//用泛型格式,如果controller返回的是页面数据,则return R.success(page);如果返回的是成功消息,则return R.success("success");如果返回错误消息,return R.error("错误原因");
@Data
public class R<T> {
 
    private Integer code; //编码:1成功,0和其它数字为失败
 
    private String msg; //错误信息
 
    private T data; //数据
 
    private Map map = new HashMap(); //动态数据
    //静态类,controller返回时直接return R.success(T);
    public static <T> R<T> success(T object) {
        R<T> r = new R<T>();
        r.data = object;
        r.code = 1;
        return r;
    }
 
    public static <T> R<T> error(String msg) {
        R r = new R();
        r.msg = msg;
        r.code = 0;
        return r;
    }
    //添加动态数据
    public R<T> add(String key, Object value) {
        this.map.put(key, value);
        return this;
    }
}

1.2 dao,service,controller

dao层:

@Mapper
public interface EmployeeDao extends BaseMapper<Employee> {
}

service层:
 

public interface EmployeeService extends IService<Employee> {
}
 
 
 
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeDao, Employee> implements EmployeeService {
}

这里业务接口继承了IService,业务实现类继承了ServiceImpl<M extends BaseMapper, T>,这样service就继承了Mybatis-plus的各方法、变量。

ServiceImpl<M extends BaseMapper, T>类各方法(未过期)的作用

getBaseMapper() getEntityClass() saveBatch() saveOrUpdate() saveOrUpdateBatch() updateBatchById() getOne() getMap() getObj() ServiceImpl类各属性的作用

log:打印日志 baseMapper:实现了许多的SQL操作 entityClass:实体类 mapperClass:映射类
 

controller层:

@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {
 
    @Autowired
    private EmployeeService employeeService;
 
    /**
     * 员工登录
     * @param request
     * @param employee
     * @return
     */
    @PostMapping("/login")
    public R<Employee> login(HttpServletRequest request,@RequestBody Employee employee){
 
        //1、将页面提交的密码password进行md5加密处理。同一个数据多次md5加密的结果是一样的,所以md5不能解密,但可以通过碰撞解密。
        String password = employee.getPassword();
        password = DigestUtils.md5DigestAsHex(password.getBytes());
 
        //2、根据页面提交的用户名username查询数据库
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Employee::getUsername,employee.getUsername());
        Employee emp = employeeService.getOne(queryWrapper);
 
        //3、如果没有查询到则返回登录失败结果
        if(emp == null){
            return R.error("用户名或密码错误");
        }
 
        //4、密码比对,如果不一致则返回登录失败结果
        if(!emp.getPassword().equals(password)){
            return R.error("登录失败");
        }
 
        //5、查看员工状态,如果为已禁用状态,则返回员工已禁用结果
        if(emp.getStatus() == 0){
            return R.error("账号已被禁用");
        }
 
        //6、登录成功,将员工id存入Session并返回登录成功结果
        //被忘了存Session,默认有效期30分钟
        request.getSession().setAttribute("employee",emp.getId());
        return R.success(emp);
    }
 
    /**
     * 员工退出
     * @param request
     * @return
     */
    @PostMapping("/logout")
    public R<String> logout(HttpServletRequest request){
        //清理Session中保存的当前登录员工的id
        request.getSession().removeAttribute("employee");
        return R.success("退出成功");
    }
}

@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {
 
    @Autowired
    private EmployeeService employeeService;
 
    /**
     * 员工登录
     * @param request
     * @param employee
     * @return
     */
    @PostMapping("/login")
    public R<Employee> login(HttpServletRequest request,@RequestBody Employee employee){
 
        //1、将页面提交的密码password进行md5加密处理。同一个数据多次md5加密的结果是一样的,所以md5不能解密,但可以通过碰撞解密。
        String password = employee.getPassword();
        password = DigestUtils.md5DigestAsHex(password.getBytes());
 
        //2、根据页面提交的用户名username查询数据库
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Employee::getUsername,employee.getUsername());
        Employee emp = employeeService.getOne(queryWrapper);
 
        //3、如果没有查询到则返回登录失败结果
        if(emp == null){
            return R.error("用户名或密码错误");
        }
 
        //4、密码比对,如果不一致则返回登录失败结果
        if(!emp.getPassword().equals(password)){
            return R.error("登录失败");
        }
 
        //5、查看员工状态,如果为已禁用状态,则返回员工已禁用结果
        if(emp.getStatus() == 0){
            return R.error("账号已被禁用");
        }
 
        //6、登录成功,将员工id存入Session并返回登录成功结果
        //被忘了存Session,默认有效期30分钟
        request.getSession().setAttribute("employee",emp.getId());
        return R.success(emp);
    }
 
    /**
     * 员工退出
     * @param request
     * @return
     */
    @PostMapping("/logout")
    public R<String> logout(HttpServletRequest request){
        //清理Session中保存的当前登录员工的id
        request.getSession().removeAttribute("employee");
        return R.success("退出成功");
    }
}

MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。

md5是一种不可逆的加密,一定记住是不可逆的。即得到密文无法还原明文。

同一个数据多次md5加密的结果是一样的,所以md5不能解密,但可以通过碰撞解密。

比如你得到一个md5加密串"E10ADC3949BA59ABBE56E057F20F883E",你有N个密码,通过md5加密加密N个密码,得到其中一个和"E10ADC3949BA59ABBE56E057F20F883E"一致,那么则密码一致。

md5解密网站(实际是靠碰撞解密):md5在线解密破解,md5解密加密
 

登出功能:删除Session

    @RequestMapping("/logout")
    public R logout(HttpServletRequest request){
        //尝试删除
        try {
            request.getSession().removeAttribute("employee");
        }catch (Exception e){
            //删除失败
            return R.error("登出失败");
        }
        return R.success("登出成功");
    }

可以看到点击退出后就清除存储信息了。

1.3 拦截页面登陆(添加过滤器,未登录状态自动跳转登录页面)

这里的话用户直接url+资源名可以随便访问,所以要加个拦截器或者过滤器,没有登陆时,不给访问,自动跳转到登陆页面。

过滤器和拦截器回顾

拦截器和过滤器之间的区别:

归属不同:Filter属于Servlet技术,依赖于Servlet容器;Interceptor属于SpringMVC技术,不依赖于servlet容器。 拦截内容不同:Filter对所有访问进行增强,几乎对所有请求起作用;Interceptor仅针对SpringMVC的访问进行增强,只能对action请求起作用。 调用次数不同:在action的生命周期中,过滤器只能在容器初始化时被调用一次,而拦截器可以多次被调用。 获取bean的权限不同:过滤器不能获取IOC容器中的各个bean;拦截器就可以,因为拦截器本身是个bean。这点很重要,在拦截器里注入一个service,可以调用业务逻辑。 底层机制不同:过滤器是基于函数回调,拦截器是基于java的反射机制的。


 

代码实现:

1.在引导类注解**@ServletComponentScan**

2.在filter包下编写过滤器

//坑点,路径是"/*",别忘了*
@WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*")
@Slf4j
public class LoginCheckFilter implements Filter{
    //路径匹配器,支持通配符,别忘了
    public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //0.要先把请求响应ServletXxx转成它的子接口HttpServletXxx,从而多了一些针对于Http协议的方法
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
 
        //1、获取本次请求的URI
        String requestURI = request.getRequestURI();// /backend/index.html
 
        log.info("拦截到请求:{}",requestURI);
 
        //定义不需要处理的请求路径,前端页面可以放行,只是除登录登出的后端拦截就行。
        String[] urls = new String[]{
                "/employee/login",
                "/employee/logout",
                "/backend/**",
                "/front/**"
        };
 
 
        //2、判断本次请求是否需要处理
        boolean check = check(urls, requestURI);
 
        //3、如果不需要处理,则直接放行
        if(check){
            log.info("本次请求{}不需要处理",requestURI);
            filterChain.doFilter(request,response);
            return;
        }
 
        //4、判断登录状态,如果已登录,则直接放行
        if(request.getSession().getAttribute("employee") != null){
            log.info("用户已登录,用户id为:{}",request.getSession().getAttribute("employee"));
            filterChain.doFilter(request,response);
            return;
        }
 
        log.info("用户未登录");
        //5、如果未登录则返回未登录结果,通过输出流方式向客户端页面响应数据
        //必须错误信息NOTLOGIN,因为前端根据msg==“NOTLOGIN”和code==0判断未登录
        response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
        return;
 
    }
 
    /**
     * 路径匹配,检查本次请求是否需要放行
     * @param urls
     * @param requestURI
     * @return
     */
    public boolean check(String[] urls,String requestURI){
        for (String url : urls) {
            //这里是坑点,不能用equals
            boolean match = PATH_MATCHER.match(url, requestURI);
            if(match){
                return true;
            }
        }
        return false;
    }
}

坑点:

  • 0.别忘了引导类注解@ServletComponentScan
  • 1.通配符/*,别忘了*号
  • 2.别忘了创建静态final对象AntPathMatcher ,用它的match()方法进行url匹配,不能用equals

响应到前端的是否登录信息将在requeset.js中处理:

其实所有前端页面都引用了js/request.js里的前端拦截器,前端拦截器完成跳转到登陆页面,不在后端做处理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1225430.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

wangEditor富文本编辑器使用

一、官网 开源 Web 富文本编辑器&#xff0c;开箱即用&#xff0c;配置简单 二、下载安装 npm install --save wangeditor/editor-for-vue 三、在vue中使用 3.1、抽离组件editor.vue 在工程的components目录下新建组件editor <template><div><Toolbar:edi…

若依框架数据源切换为pg库

一 切换数据源 在ruoyi-admin项目里引入pg数据库驱动 <dependency><groupId>org.postgresql</groupId><artifactId>postgresql</artifactId><version>42.2.18</version> </dependency>修改配置文件里的数据源为pg spring:d…

神经网络反向传播的数学原理

如果能二秒内在脑袋里解出下面的问题&#xff0c;本文便结束了。 已知&#xff1a;&#xff0c;其中。 求&#xff1a;。 到这里&#xff0c;请耐心看完下面的公式推导&#xff0c;无需长久心里建设。 首先&#xff0c;反向传播的数学原理是“求导的链式法则” : 设f和g为x…

多因素方差分析(Multi-way Analysis of Variance) R实现

1, data0507 flower 是某种植物在两个海拔和两个气温下的开花高度&#xff0c;采用合适 的统计方法&#xff0c;检验该种植物的开花高度在不同的海拔之间和不同的气温之间有无差异&#xff1f;如果有差异&#xff0c;具体如何差异的&#xff1f;&#xff08;说明依据、结论等关…

春秋云境靶场CVE-2022-28512漏洞复现(sql手工注入)

文章目录 前言一、CVE-2022-28512靶场简述二、找注入点三、CVE-2022-28512漏洞复现1、判断注入点2、爆显位个数3、爆显位位置4 、爆数据库名5、爆数据库表名6、爆数据库列名7、爆数据库数据 总结 前言 此文章只用于学习和反思巩固sql注入知识&#xff0c;禁止用于做非法攻击。…

Learning Perception Module

参考文章&#xff1a;自动驾驶开发者说|框架|如何单独运行apollo相机感知模块&#xff1f; - 知乎引言文章主要尝试了apollo框架下&#xff0c;视觉感知模块的单独运行&#xff0c;并利用离线的数据包进行检测实时展示结果。过程相对来说比较顺利。在加上已经用VScode搭建的单步…

springboot321基于java的校园服务平台设计与开发

交流学习&#xff1a; 更多项目&#xff1a; 全网最全的Java成品项目列表 https://docs.qq.com/doc/DUXdsVlhIdVlsemdX 演示 项目功能演示&#xff1a; ————————————————

解决:ERROR: No matching distribution found for PIL

解决&#xff1a;ERROR: No matching distribution found for PIL 背景 在搭建之前的代码环境时&#xff0c;报错&#xff1a; ERROR: Could not find a wersion that satisfies the requirement PIL&#xff08;from versions: none&#xff09; ERROR: No matching distribu…

机器视觉系统选型-定光照强度

同一个外形结构的光源&#xff0c;光照强度受如下影响&#xff1a; 单颗灯珠的亮度灯珠排列的数量和密度漫射板/防护板的材质&#xff08;透明、半透明、全漫射&#xff09; 在合理范围内提升光照强度&#xff0c;可降低对相机曝光时长的要求 外形结构尺寸相同的两款光源&am…

基于SSM的古董拍卖系统

基于SSM的古董拍卖系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringMyBatisSpringMVC工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 拍卖界面 管理员界面 摘要 古董拍卖系统是一个基于SSM框架&#xff08;Spring …

Linux yum 使用时提示 获取 GPG 密钥失败Couldn‘t open file RPM-GPG-KEY-EPEL-7

资料 错误提示&#xff1a; no crontab for root - using an empty one 888 原因剖析&#xff1a; 第一次使用crontab -e 命令时会让我们选择编辑器&#xff0c;很多人会不小心选择默认的nano&#xff08;不好用&#xff09;&#xff0c;或则提示no crontab for root - usin…

Java拼图游戏

运行出的游戏界面如下&#xff1a; 按住A不松开&#xff0c;显示完整图片&#xff1b;松开A显示随机打乱的图片。 User类 package domain;/*** ClassName: User* Author: Kox* Data: 2023/2/2* Sketch:*/ public class User {private String username;private String password…

进程概述

文章目录 计算机算机组成因特尔CPU型号摩尔定律衡量CPU的指标指令&#xff08;Instruction)操作系统&#xff08;Operating System&#xff09;虚拟地址空间&#xff08;Virtual Address Space&#xff09;进程(Process/task)进程管理(PCB - 进程控制块)进程控制块&#xff08;…

一文讲明 Spring 的使用 【全网超详细教程】

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 前言 目录结构 Spring 的相关代码 都公开在…

分类预测 | Matlab实现基于SDAE堆叠去噪自编码器的数据分类预测

分类预测 | Matlab实现基于SDAE堆叠去噪自编码器的数据分类预测 目录 分类预测 | Matlab实现基于SDAE堆叠去噪自编码器的数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现基于SDAE堆叠去噪自编码器的数据分类预测&#xff08;完整源码和数据) 2.多…

Linux procps-ng - top

procps-ng 是一个开源的进程管理工具集&#xff0c;它提供了一系列用于监控和管理系统进程的命令行工具。它是 procps 工具集的一个分支&#xff0c;旨在改进和增强原有的 procps 工具。 procps-ng 包括了一些常用的命令行工具&#xff0c;例如&#xff1a; ps&#xff1a;用于…

【漏洞复现】泛微e-Weaver SQL注入

漏洞描述 泛微e-Weaver&#xff08;FANWEI e-Weaver&#xff09;是一款广泛应用于企业数字化转型领域的集成协同管理平台。作为中国知名的企业级软件解决方案提供商&#xff0c;泛微软件&#xff08;广州&#xff09;股份有限公司开发和推广了e-Weaver平台。 泛微e-Weaver旨在…

springBoot 配置druid多数据源 MySQL+SQLSERVER

1:pom 文件引入数据 <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.0</version> </dependency>…

前端性能优化之LightHouse

优质博文&#xff1a;IT-BLOG-CN 一、LightHouse环境搭建 LightHouse是一款由Google开发的开源工具&#xff0c;用于评估Web应用程序的性能和质量。可以将其看作是一个Chrome扩展程序运行&#xff0c;或从命令行运行。为LightHouse提供一个需要审查的网址&#xff0c;它将针对…

基于django的在线教育系统

基于python的在线教育系统 摘要 基于Django的在线教育系统是一种利用Django框架开发的现代化教育平台。该系统旨在提供高效、灵活、易用的在线学习体验&#xff0c;满足学生、教师和管理员的需求。系统包括学生管理、课程管理、教师管理、视频课程、在线测验等核心功能。系统采…