Spring:强制登陆与拦截器

news2024/11/16 17:54:25

1.只使用session验证

(1)第一步:用户登陆时存储session

@ApiOperation("用户登陆")
@PostMapping("/login")
public AppResult login(HttpServletRequest request,
                           @RequestParam("username") @ApiParam("用户名") @NonNull String username,
                           @RequestParam("password") @ApiParam("用户密码") @NonNull String password) {
        //1.参数校验 -- 注解已完成
        //2.调用service层
        User user = userService.login(username, password);
        //3.设置session
        HttpSession session = request.getSession(true);
        session.setAttribute(AppConfig.USER_SESSION,user);
        return AppResult.success();
}

关键代码:

HttpServletRequest request
 //3.设置session
        HttpSession session = request.getSession(true);
        session.setAttribute(AppConfig.USER_SESSION,user);//存储的是key-value

 

(2)第二步:访问接口时验获取session

@ApiOperation("查询用户信息")
@GetMapping("/info")
public AppResult<User> getUserInfo(HttpServletRequest request) {
    log.info("获取用户信息");
    User user = null;
    HttpSession session = request.getSession(false);
    if(session == null || session.getAttribute(AppConfig.USER_SESSION) == null) {
        //用户未登录
       return AppResult.failed(ResultCode.FAILED_FORBIDDEN);
    }
    user = (User) session.getAttribute(AppConfig.USER_SESSION);
    }
    if(user == null) {
        return AppResult.failed(ResultCode.FAILED_FORBIDDEN);
    }
    return AppResult.success(user);
}

关键代码:

HttpServletRequest request//参数
HttpSession session = request.getSession(false);
if(session == null || session.getAttribute(AppConfig.USER_SESSION) == null) {
   //用户未登录
   return AppResult.failed(ResultCode.FAILED_FORBIDDEN);
}

只要获取不到session或者不能从session中获取到对象,就说明用户没有登陆。 


上述就是只使用session进行强制用户登陆的写法,需要在每个方法都进行判断。 

2.使用拦截器强制登录和session

上述是没有引入拦截器的场景,每个部分都需要引入相同的代码,就会使得代码非常的繁琐,所以我们就可以使用Spring统一功能中的拦截器。

简单介绍拦截器:由两个部分组成

第一个部分:定义拦截器(也就是指定拦截规则,比如没有session就不允许访问);第二个部分:配置拦截器,也就是执行这些规则(比如把保安投放到某某路口等)

(1)第一步:定义拦截器

语法:实现HandlerInterceptor接口,并重写其所有方法

@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse    
response, Object handler) throws Exception {
        log.info("LoginInterceptor ⽬标⽅法执⾏前执⾏..");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse
response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("LoginInterceptor ⽬标⽅法执⾏后执⾏");
    }
    @Override
    public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("LoginInterceptor 视图渲染完毕后执⾏,最后执⾏");
    }
}

其中里面有三个重写的方法,一般我们只需要重写第一个就够了,就是我们需要的拦截器

(1)preHeandle:目标方法前执行该方法(比如执行获取用户信息的方法前,会先执行该方法)。该方法返回true,后面的方法继续执行(不拦截);返回false,后面的方法中断。

(2)postHandle:目标方法执行后就会执行该方法。

(3)afterCompletion:视图渲染完毕后执行,最后执行(后端开发现在几乎不涉及视图,暂不了解)

定义拦截器:基本模版

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Slf4j
//把对象交给Spring管理,否则不生效
@Component
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1.获取session
        HttpSession session = request.getSession(false);
        //2.判断是否存在session或者用户已登录
        if(session != null && session.getAttribute("user") != null) {
            //进入该方法,说明用户已登录,就不进行拦截操作
            return true;
        }
        //3.走到这一步,说明用户未登录,进行拦截(也可以指定跳转某一个页面)
        response.sendRedirect("/login.html");//设置跳转的页面,一般为登陆页面
        return false;//拦截并跳转
    }
}

上面就是配置拦截器的基本代码模版,有一个注意点:跳转的页面最好是封装成一个常量,利于后续的修改操作。

(2)第二步:配置拦截器

上面的第一步我们已经定义好了拦截规则,下面只需要配置就好(上面已经规定了哪些人员不准进入小区,接下来我们需要投放保安到小区的指定路口进行拦截)

语法:WebMvcConfigurer接口,并重写addInterceptors方法

基本模版:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class AppInterceptorConfigurer implements WebMvcConfigurer {

    @Autowired
    private LoginInterceptor loginInterceptor;//给保安们注入拦截规则

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)//该方法是注册,也就是执行拦截规则
                .addPathPatterns("/**")//该方法表示拦截所有的请求
                .excludePathPatterns("/login");//表示该页面不进行拦截
    }
}

上面就是模版,一般登录页面和注册等页面我们都是不进行拦截的,要是拦截住了就死锁了。

然后对于要拦截什么页面,看大家的需求;对于拦截器+session的介绍就结束了,也就是上面的两段代码。

3.使用令牌拦截

使用令牌技术生成一个token字符串用来验证用户是否登陆

下面是关于用户登陆和验证的基本步骤: 

 (1)前端发送登陆请求,后端进行验证

(2)后端验证通过,返回token

(3)客户端存储token(通过前端进行操作)

(4)客户端后续发起的请求,就会把token放在请求的header中(k-v的形式,token存储在v中)

(5)后端从header中获取到token(指定前端的k,才能获取token),进行验证

这个部分前面先介绍如何在代码中使用登陆令牌,后面再介绍代码的含义

使用步骤大致分为四步:引入依赖、编写令牌工作类、发放令牌、验证令牌

(1)第一步:引入依赖

引入pom依赖,需要使用到令牌专属的类

<!--  jwt令牌  -->
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
     <!-- or jjwt-gson if Gson is preferred -->
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>

引入后记得刷新maven

(2)第二步:编写令牌工具utils

在主目录下创建utils包,再创建JwtUtils类

//负责生成令牌和验证令牌

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;

import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class JwtUtils {


    private static long expiration =  30 * 60 * 1000;  //规定令牌有效期为30分钟
    private static String secretString = "gaiosfhioawjfajrawrawrawrawrawrawrawrfjarawrawrawrafawfoawjfa";
    private static Key key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretString));//key值,数字签名

    /**
     * 生成令牌
     */
    public static String genJwt(Map<String, Object> data) {
        //生产token
        String compact = Jwts.builder()//固定方法
                        .setClaims(data)//设置数据
                        .setExpiration(new Date(System.currentTimeMillis()+expiration))//设置token的过期时间
                        .signWith(key)//设置数字签名
                        .compact();//生产token
        return compact;
    }

    /**
     * 校验令牌
     */
    public static Claims verify(String token){
        //生成token用的都是同一个key,所以不需要传参
        //获取build对象
        JwtParser build = Jwts.parserBuilder().setSigningKey(key).build();

        Claims claims = null;
        try {
            claims = build.parseClaimsJws(token).getBody();//与token校验
        }catch (ExpiredJwtException e){
            log.error("token过期, 校验失败, token:"+ token);
        }catch (Exception e){
            log.error("token校验失败, token:"+ token);
        }
        return claims;
    }

}

作用:这个类提供两个静态方法,第一个是负责生成令牌,第二个是负责验证令牌。

上述的生成和验证令牌属于大致模版,自己也可以进行大致的修改

(3)第三步:后端发放令牌

一般在登陆接口给用户发放令牌。

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {


    @RequestMapping("/login")
    public Result login(String userName, String password){
        //前面一堆验证工作,这里根据自己的业务功能写
        //………………
        UserInfo userInfo = new UserInfo();
        //账目密码验证完成,就可以给用户发放令牌了
        Map<String,Object> cliams = new HashMap<>();
        cliams.put("id", userInfo.getId());
        cliams.put("name", userInfo.getUserName());
        //获取对应的token
        String jwt = JwtUtils.genJwt(cliams);
        //返回token
        return Result.success(jwt);
    }
}

在验证完用户信息后,就可以给用户设置令牌并且返回token了,token中设置的信息一般不要设置隐私信息,比如用户密码

(4)第四步:后续验证令牌

这里直接采取统一拦截器进行拦截了,下面是关于拦截规则的代码

这一步作为纯后端程序猿来说比较困难,因为要和前端的参数进行同步。前端会把token(一个字符串)以k-v的形式放入header中,所以可以从请求中进行获取

@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //验证token是否合法
        String userToken = request.getHeader("user_token_header");
        log.info("从header中获取信息, token:"+ userToken);
        Claims claims = JwtUtils.verify(userToken);
        if (claims==null){
            //token校验失败
            response.setStatus(401);
//            response.getOutputStream().write();
//            response.setContentType();
            return false;
        }
        return true;
    }
}

user_token_header是请求头中的key,用来获取对应的value值,也就是token

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

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

相关文章

将上一篇的feign接口抽取到公共api模块(包含feign接口示例)

文章目录 一、准备二、主要工作三、建立dto类四、添加多个feign接口五、测试六、目录结构6.1 父工程service-demo6.2 order-service模块6.3 product-service模块6.4 sd-api模块 一、准备 将上一篇的目录结构改造一下&#xff1a; 修改包名使根路径分别为com.hdl.order和com.h…

微信支付:chooseWXPay:fail, the permission value is offline verifying

在开发公众号微信支付的时候&#xff0c;在微信开发者工具中使用 WeixinJSBridge 唤起 微信支付&#xff0c;页面上看到微信支付的loading一闪而过&#xff0c;但是没有出现微信支付的页面。控制台log显示错误信息&#xff1a;“chooseWXPay:fail, the permission value is off…

实验1 Python语言基础一

目录 实验1 Python语言基础一1、下载安装Python&#xff0c;贴出验证安装成功截图2、建立test.py文件,运行后贴出截图&#xff0c;思考if __name”__main__”的意思和作用3、分别运行下面两种代码&#xff0c;分析运行结果产生的原因。记牢python中重要语法“tab”的作用。6、编…

企业内训|大模型/智算行业发展机会深度剖析-某数据中心厂商

北京中嘉和信通信技术有限公司于8月29日举办了一场主题为“大模型/智算行业发展机会深度剖析”的企业内训。此次培训由TsingtaoAI公司负责人汶生主讲&#xff0c;针对当前大模型技术的发展现状、应用场景及未来趋势进行了全面分析和解读。 汶生老师在培训中深入剖析了大模型的…

京东商品详情API(item_get)性能优化策略:提升数据抓取效率

在电商领域&#xff0c;快速、准确地获取商品信息对于提升用户体验、优化库存管理和市场决策至关重要。京东商品详情API&#xff08;item_get&#xff09;作为京东开放平台提供的一项重要服务&#xff0c;允许开发者获取京东平台上商品的详细信息。然而&#xff0c;如何高效利用…

xxl-job 适配达梦数据库

前言 在数字化转型的浪潮中&#xff0c;任务调度成为了后端服务不可或缺的一部分。XXL-JOB 是一个轻量级、分布式的任务调度框架&#xff0c;广泛应用于各种业务场景。达梦数据库&#xff08;DM&#xff09;&#xff0c;作为一款国内领先的数据库产品&#xff0c;已经被越来越…

详解调用钉钉AI助理消息API发送钉钉消息卡片给指定单聊用户

文章目录 前言准备工作1、在钉钉开发者后台创建一个钉钉企业内部应用&#xff1b;2、创建并保存好应用的appKey和appSecret&#xff0c;后面用于获取调用API的请求token&#xff1b;3、了解AI助理主动发送消息API&#xff1a;4、应用中配置好所需权限&#xff1a;4.1、权限点4.…

光控资本:国庆节股市能不能继续交易?A股放量大涨

早年这个时分&#xff0c;商场谈论的最多论题是&#xff0c;持股过节仍是持币过节。 而本年却大不一样&#xff0c;“国庆节股市能不能继续生意”成为这两天股民之间的梗。 今天上午&#xff0c;A股继续暴升&#xff0c;创了三个纪录。一是上午成交额为9466亿元&#xff0c;跨…

2024 maya的散布工具sppaint3d使用指南

目前工具其实可以分为三个版本 1 最老的原版 时间还是2011年的&#xff0c;只支持python2版的maya 2 作者python3更新版 后来作者看maya直到2022上还是没有类似好用方便的工具&#xff0c;于是更新到了2022版本 这个是原作者更新的2022版本&#xff0c;改成了python3&#…

一款开源的通用PDF处理神器,功能强悍!

文章目录 前言一、简介二、功能三、安装1.二进制安装2.编译安装 四、开源地址 前言 PDF是一种功能强大且广泛应用的电子文档格式&#xff0c;适用于各种文档管理和共享需求。由于PDF文档注重阅读而非编辑&#xff0c;很多文档处理会让我们非常头疼。 网上有非常多的PDF相关的…

re轻松拆分四则运算expression(^从头匹配、(?:xxxx)非捕获组、| 交替运算符联合演习)

与ai对抵聊“算式匹配”&#xff0c;发现^从头匹配、(?:xxxx)非捕获组、| “交替”运算符联合使用的妙处。 (笔记模板由python脚本于2024年09月27日 18:35:32创建&#xff0c;本篇笔记适合喜欢python喜欢正则的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;…

《GC8545:智能马桶电路板的卓越替代之选》

在智能马桶领域&#xff0c;电路板的性能至关重要。随着技术的不断发展&#xff0c;寻找更优质、更高效的芯片来替代传统型号已成为行业的趋势。而 GC8545 芯片以其卓越的性能和广泛的适用性&#xff0c;正逐渐成为替代其他型号的理想选择。其中最常用的就是替代的型号LV8548和…

【machine learning-13-线性回归的向量化】

向量化 向量化简洁并行计算 向量化 线性回归的向量化表示如下&#xff0c;其中w 和 x 都分别加了箭头表示这是个向量&#xff0c;后续不加也可以表示为向量&#xff0c;w和x点乘加上b&#xff0c;就构成了多元线性回归的表达方式&#xff0c;如下&#xff1a; 那么究竟为什么…

产品管理-互联网产品(2):需求管理

一、概述 需求问题解决方案&#xff0c;产品经理是解决问题专家。提出求产品经理需要考虑如下四点&#xff1a; 1、客户的目的是什么&#xff1f;2、这条需求是否隐含了解决方案&#xff1f;3、客户的潜在目标是什么&#xff1f;4、如何确定需求已得到满足&#xff1f; 二、…

SD NAND参考设计和使用提示

电路设计 参考电路&#xff1a; R1~R5 (10K-100 kΩ)是上拉电阻&#xff0c;当SD NAND处于高阻抗模式时&#xff0c;保护CMD和DAT线免受总线浮动。 即使主机使用SD NAND SD模式下的1位模式&#xff0c;主机也应通过上拉电阻上拉所有的DATO-3线。 R6&#xff08;RCLK&#…

[数据结构] 二叉树题目 (二)

目录 一. 另一颗树的子树 1.1 题目 1.2 示例 1.3 分析 1.4 解决 二. 平衡二叉树 2.1 题目 2.2 示例 2.3 分析 2.4 解决 三. 二叉树的遍历和创建 3.1 题目 3.2 示例 3.3 解决 一. 另一颗树的子树572. 另一棵树的子树 - 力扣&#xff08;LeetCode&#xff09; 1.1…

Linux开源网络:网络虚拟化

Linux 网络虚拟化的主要技术是网络命名空间以及各类虚拟网络设备。例如要介绍的 veth、Linux bridge、tun/tap 等&#xff0c;这些虚拟网络设备模拟了物理设备的功能&#xff0c;但完全在内核层面由代码实现。容器网络正是基于这些虚拟网络设备&#xff0c;模拟现实世界中的物理…

《自控原理》系统传递函数的零极点模型、分式模型、系统增益

目录 传递函数模型与零极点 系统增益 《自动控制原理》胡寿松&#xff0c;第六版 传递函数模型与零极点 (3-61)所示的是系统的传递函数的分式形式。他一定可以化成&#xff08;3-62&#xff09;形式。 根据3-62的分母可以直接看出系统的特征根&#xff0c;不过要注意&#…

前端框架对比与选择:全面解析前端开发的得力助手

一、引言 在当今快速发展的互联网时代&#xff0c;前端开发扮演着至关重要的角色。前端框架的出现极大地提高了开发效率、提升了用户体验。然而&#xff0c;市场上存在着众多的前端框架&#xff0c;如React、Vue、Angular等&#xff0c;对于开发者来说&#xff0c;如何在这些框…

使用 Paramiko 实现 SSH 远程连接和命令执行

使用 Paramiko 实现 SSH 远程连接和命令执行 每当灶火燃起&#xff0c;香气弥漫&#xff0c;熟悉的味道植入记忆深处&#xff0c;家&#xff0c;才获得完整的意义。万户千家&#xff0c;味道迥异&#xff0c;但幸福的滋味&#xff0c;却何其相同。 ——《风味人间》 在现代网络…