首页 > 其他分享 >解决密码校验问题

解决密码校验问题

时间:2023-04-16 22:57:55浏览次数:43  
标签:令牌 请求 登录 jwt 校验 密码 Cookie 解决 过滤器

密码教研中的问题

http协议是无状态的协议,每次请求间不能实现数据共享.

这样的状况下,不能在后续请求中获取是否登录的数据

解决方法

1. 在员工登录成功后,需要将用户登录成功的信息存起来,记录用户已经登录成功的标记。
2. 在浏览器发起请求时,需要在服务端进行统一拦截,拦截后进行登录校验。

过统一拦截的技术,我们可以来拦截浏览器发送过来的所有的请求,拦截到这个请求之后
,就可以通过请求来获取之前所存入的登录标记,在获取到登录标记且标记为登录成功,
就说明员工已经登录了。如果已经登录,我们就直接放行

会话技术

什么是会话

web开发当中,会话指的就是浏览器与服务器之间的一次连接,我们就称为一次会话。(只要服务器和浏览器连接没有断开,多次请求也是一次会话)

什么是会话跟踪

一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据。
使用会话跟踪技术完成同一次会话中多次请求的数据共享

二种会话跟踪技术:

1.cookie(客户端会话跟踪技术)

数据存储在客户端浏览器

cookie 是客户端会话跟踪技术,它是存储在客户端浏览器的,我们使用 cookie 来跟踪会话,我们就可以在浏览器第一次发起请求来请求服务器的时候,我们在服务器端来设置一个cookie。

比如第一次请求了登录接口,登录接口执行完成之后,我们就可以设置一个cookie,在 cookie 当中我们就可以来存储用户相关的一些数据信息。比如我可以在 cookie 当中来存储当前登录用户的用户名,用户的ID。

服务器端在给客户端在响应数据的时候,会自动的将 cookie 响应给浏览器,浏览器接收到响应回来的 cookie 之后,会自动的将 cookie 的值存储在浏览器本地。接下来在后续的每一次请求当中,都会将浏览器本地所存储的 cookie 自动地携带到服务端。

为什么自动进行?

因为cookie是http中支持的技术

在协议官方给我们提供了响应头和请求头

  • 响应头 Set-Cookie :设置Cookie数据的

  • 请求头 Cookie:携带Cookie数据的

 

优缺点

  • 优点:HTTP协议中支持的技术(像Set-Cookie 响应头的解析以及 Cookie 请求头数据的携带,都是浏览器自动进行的,是无需我们手动操作的)

  • 缺点:

    • 移动端APP(Android、IOS)中无法使用Cookie

    • 不安全,用户可以自己禁用Cookie

    • Cookie不能跨域

什么是跨域

在一个域名页面访问另一个不同域名下的接口

  • 协议

  • IP/协议

  • 端口

只要上述的三个维度有任何一个维度不同,那就是跨域操作



2.session(服务端会话跟踪技术)

数据存储在服务端

浏览器在第一次请求服务器的时候,我们就可以直接在服务器当中来获取到会话对象Session。如果是第一次请求Session ,会话对象是不存在的,这个时候服务器会自动的创建一个会话对象Session 。而每一个会话对象Session ,它都有一个ID(示意图中Session后面括号中的1,就表示ID),我们称之为 Session 的ID。

接下来,服务器端在给浏览器响应数据的时候,它会将 Session 的 ID 通过 Cookie 响应给浏览器。其实在响应头当中增加了一个 Set-Cookie 响应头。这个 Set-Cookie 响应头对应的值是不是cookie? cookie 的名字是固定的 JSESSIONID 代表的服务器端会话对象 Session 的 ID。浏览器会自动识别这个响应头,然后自动将Cookie存储在浏览器本地。

接下来,在后续的每一次请求当中,都会将 Cookie 的数据获取出来,并且携带到服务端。接下来服务器拿到JSESSIONID这个 Cookie 的值,也就是 Session 的ID。拿到 ID 之后,就会从众多的 Session 当中来找到当前请求对应的会话对象Session。

优缺点

  • 优点:Session是存储在服务端的,安全

  • 缺点:

    • 服务器集群环境下无法直接使用Session

    • 移动端APP(Android、IOS)中无法使用Cookie

    • 用户可以自己禁用Cookie

    • Cookie不能跨域

    • PS:Session 底层是基于Cookie实现的会话跟踪,如果Cookie不可用,则该方案,也就失效了。

令牌技术

 jwt令牌

一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。

JWT的组成: (JWT令牌由三个部分组成,三个部分之间使用英文的点来分割)

  • 第一部分:Header(头), 记录令牌类型、签名算法等。 例如:{"alg":"HS256","type":"JWT"}

  • 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:{"id":"1","username":"Tom"}

  • 第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。

 

JWT令牌最典型的应用场景就是登录认证:

  1. 在浏览器发起请求来执行登录操作,此时会访问登录的接口,如果登录成功之后,我们需要生成一个jwt令牌,将生成的 jwt令牌返回给前端。

  2. 前端拿到jwt令牌之后,会将jwt令牌存储起来。在后续的每一次请求中都会将jwt令牌携带到服务端。

  3. 服务端统一拦截请求之后,先来判断一下这次请求有没有把令牌带过来,如果没有带过来,直接拒绝访问,如果带过来了,还要校验一下令牌是否是有效。如果有效,就直接放行进行请求的处理。

 

在JWT登录认证的场景中我们发现,整个流程当中涉及到两步操作:

  1. 在登录成功之后,要生成令牌。

  2. 每一次请求当中,要接收令牌并对令牌进行校验。

生产jwt令牌

引入依赖

<!-- JWT依赖-->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

@Test
public void genJwt(){
    Map<String,Object> claims = new HashMap<>();
    claims.put("id",1);
    claims.put("username","Tom");
    
    String jwt = Jwts.builder()
        .setClaims(claims) //自定义内容(载荷)          
        .signWith(SignatureAlgorithm.HS256, "itheima") //签名算法        
        .setExpiration(new Date(System.currentTimeMillis() + 24*3600*1000)) //有效期   
        .compact();
    
    System.out.println(jwt);
}

校验令牌

@Test
public void parseJwt(){
    Claims claims = Jwts.parser()
        .setSigningKey("itheima")//指定签名密钥
.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjczMDA5NzU0fQ.RcVIR65AkGiax-ID6FjW60eLFH3tPTKdoK7UtE4A1ro")
        .getBody();

    System.out.println(claims);
}

利用jwt实现用户登录的认证

1.引入工具类

public class JwtUtils {

    private static String signKey = "itheima";//签名密钥
    private static Long expire = 43200000L; //有效时间

    /**
     * 生成JWT令牌
     * @param claims JWT第二部分负载 payload 中存储的内容
     * @return
     */
    public static String generateJwt(Map<String, Object> claims){
        String jwt = Jwts.builder()
                .addClaims(claims)//自定义信息(有效载荷)
                .signWith(SignatureAlgorithm.HS256, signKey)//签名算法(头部)
                .setExpiration(new Date(System.currentTimeMillis() + expire))//过期时间
                .compact();
        return jwt;
    }

    /**
     * 解析JWT令牌
     * @param jwt JWT令牌
     * @return JWT第二部分负载 payload 中存储的内容
     */
    public static Claims parseJWT(String jwt){
        Claims claims = Jwts.parser()
                .setSigningKey(signKey)//指定签名密钥
                .parseClaimsJws(jwt)//指定令牌Token
                .getBody();
        return claims;
    }
}

2.登录成功,生成令牌并返回

@RestController
@Slf4j
public class LoginController {
@Autowired
private EmpService empService;
@PostMapping("/login")
private Result login(@RequestBody Emp emp){
Emp e = empService.login(emp);
if(e!=null){//用户名密码正确
Map<String,Object> claims=new HashMap<>();
claims.put("id",e.getId());
claims.put("username",e.getUsername());
claims.put("name",e.getName());
String jwt = JwtUtils.generateJwt(claims);
return Result.success(jwt);
}
return Result.error("用户名或密码错误");

}
}

过滤器Filter

什么是Filter?

  • Filter表示过滤器,是 JavaWeb三大组件(Servlet、Filter、Listener)之一。

  • 过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能

    • 使用了过滤器之后,要想访问web服务器上的资源,必须先经过滤器,过滤器处理完毕之后,才可以访问对应的资源。

  • 过滤器一般完成一些通用的操作,比如:登录校验、统一编码处理、敏感字符处理等。

如何使用?

  • 第1步,定义过滤器 :1.定义一个类,实现 Filter 接口,并重写其所有方法。

  • 第2步,配置过滤器:Filter类上加 @WebFilter 注解,配置拦截资源的路径。引导类上加 @ServletComponentScan 开启Servlet组件支持

  • 过滤器当中我们拦截到了请求之后,如果希望继续访问后面的web资源,就要执行放行操作,放行就是调用 FilterChain对象当中的doFilter()方法,在调用doFilter()这个方法之前所编写的代码属于放行之前的逻辑。

@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {
    
    @Override //初始化方法, 只调用一次
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init 初始化方法执行了");
    }
    
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        
        System.out.println("DemoFilter   放行前逻辑.....");

        //放行请求
        filterChain.doFilter(servletRequest,servletResponse);

        System.out.println("DemoFilter   放行后逻辑.....");
        
    }

    @Override //销毁方法, 只调用一次
    public void destroy() {
        System.out.println("destroy 销毁方法执行了");
    }
}

过滤器链

 

 

在我们web服务器当中,定义了两个过滤器,这两个过滤器就形成了一个过滤器链。

而这个链上的过滤器在执行的时候会一个一个的执行,会先执行第一个Filter,放行之后再来执行第二个Filter,如果执行到了最后一个过滤器放行之后,才会访问对应的web资源。

访问完web资源之后,按照我们刚才所介绍的过滤器的执行流程,还会回到过滤器当中来执行过滤器放行后的逻辑,而在执行放行后的逻辑的时候,顺序是反着的。

先要执行过滤器2放行之后的逻辑,再来执行过滤器1放行之后的逻辑,最后在给浏览器响

应数据。

以注解方式配置的Filter过滤器,它的执行优先级是按时过滤器类名的自动排序确定的,类名排名越靠前,优先级越高。

登录校验-Filter

 

 

基于上面的业务流程,我们分析出具体的操作步骤:

  1. 获取请求url

  2. 判断请求url中是否包含login,如果包含,说明是登录操作,放行

  3. 获取请求头中的令牌(token)

  4. 判断令牌是否存在,如果不存在,返回错误结果(未登录)

  5. 解析token,如果解析失败,返回错误结果(未登录)

  6. 放行

//@WebFilter("/*")
@Slf4j
public class LoginFilter implements Filter {

    @Autowired
    private ObjectMapper objectMapper; //@ResponseBody注解底层就是使用这个对象将java对象转成json响应给客户端

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest req = (HttpServletRequest) request;
        //1 获取请求url
        String url = req.getRequestURL().toString();
        log.info("拦截器拦截到请求:{}" , url);
        //2 判断请求url是否包含login,如果包含,说明是登录操作,放行
        if (url.contains("login")) {
            log.info("登录请求,直接放行...");
            //说明是登录操作,放行
            chain.doFilter(req,response);
            return;
        }
        //3 获取请求头中的令牌(token)
        String jwt = req.getHeader("token");
        //4 判断令牌是否存在,如果不存在,返回错误结果(未登录)
        if(!StringUtils.hasText(jwt)){
            //4.1 使用Result封装错误结果
            Result result = Result.error("NOT_LOGIN");
            //4.2 将Result转换成json,使用response响应给客户端
            objectMapper.writeValue(response.getWriter(),result);
            //返回值表示是否放行,true表示放行,false表示阻止向下执行
            return;
        }
        //5 解析token,如果解析失败,返回错误结果(未登录)
        try {
            JwtUtils.parseJWT(jwt);
        } catch (Exception e) {
            e.printStackTrace();
            //有异常就说明jwt校验失败,响应错误信息
            //4.1 使用Result封装错误结果
            Result result = Result.error("NOT_LOGIN");
            //4.2 将Result转换成json,使用response响应给客户端
            objectMapper.writeValue(response.getWriter(),result);
            //返回值表示是否放行,true表示放行,false表示阻止向下执行
            return;
        }
        //6 放行
        chain.doFilter(req,response);
    }
}

拦截器 Interceptor

是一种动态拦截方法调用的机制,类似于过滤器

拦截器是Spring框架中提供的,用来动态拦截控制器方法的执行。

 

标签:令牌,请求,登录,jwt,校验,密码,Cookie,解决,过滤器
From: https://www.cnblogs.com/zlsame/p/17318418.html

相关文章

  • 解决子级用css float浮动 而父级div没高度不能自适应高度
    解决子级对象使用cssfloat浮动而父级div不能自适应高度,不能被父级内容撑开解决方法,父级div没有高度解决方法。当在对象内的盒子使用了float后,导致对象本身不能被撑开自适应高度,这个是由于浮动产生原因。如何解决父div对象自适应高度,方法有三种,接下来DIVCSS5逐一介绍。方法一:对父......
  • React onBlur回调中使用document.activeElement返回body解决方案
    最开始想实现一个功能,点击img图标后给出购物下拉框CartDropdown,当img及CartDropdown失去焦点时隐藏CartDropdown。最开始的核心代码如下:exportdefaultfunctionCart(){ const[isCartOpen,setIsCartOpen]=useState(false) functionclickHandler(){ setIsCartOpen(......
  • 解决flex布局中justify-content设置成space-between后因数据问题导致最后一行布局错乱
    在常用的flex布局中,当页面展示商品时,因为数据的不确定,导致justify-content设置成space-between,最后一行布局错乱1<!DOCTYPEhtml>2<htmllang="en">3<head>4<metacharset="UTF-8">5<metahttp-equiv="X-UA-Compatible"conten......
  • 实验一 密码引擎-4-国䀄算法交叉测试
    任务详情02人一组,创建一个文件,文件名为小组成员学号,内容为小组成员学号和姓名1在Ubuntu中使用OpenSSL用SM4算法加密上述文件,然后用龙脉eKey解密,提交代码和运行结果截图2在Ubuntu中基于OpenSSL产生一对公私钥对(SM2算法)3在Ubuntu中使用OpenSSL用SM3算法计算上述文件的Hash......
  • 半导体企业ERP系统是什么?能为半导体企业实际解决哪些问题?
    一、什么是半导体企业ERP系统?1、半导体企业ERP系统是一种企业资源规划(ERP)系统,它是专门为半导体企业开发的,可以帮助企业在生产管理中实现集成化、自动化和数据化。2、该系统可以涵盖企业的各个方面,包括销售、采购、库存、生产计划、生产执行、品质管理等。3、通过半导体......
  • # 密码引擎-4-国䀄算法交叉测试
    任务详情2人一组,创建一个文件,文件名为小组成员学号,内容为小组成员学号和姓名在Ubuntu中使用OpenSSL用SM4算法加密上述文件,然后用龙脉eKey解密,提交代码和运行结果截图在Ubuntu中基于OpenSSL产生一对公私钥对(SM2算法)在Ubuntu中使用OpenSSL用SM3算法计算上述文件的Hash值,然后用O......
  • 解决IDEA创建项目时无法引入依赖问题:Cannot resolve **.**.**(已解决)
    今天在创建SpringBoot整合MyBatis项目时出现报错:Cannotresolveorg.springframework:spring-tx:5.3.26Cannotresolveorg.mybatis:mybatis:3.5.11Cannotresolveorg.springframework:spring-jdbc:5.3.26在网上查找了很多方法均不适用,开始以为又是版本的问题,可是一想Spring......
  • 【ArcPy】如何在ArcPy创建要素中生成精准的XY坐标?解决精度损失问题
    使用ArcPy创建要素的代码段前面有发布,【arcpy】创建点、线、面(孔洞、环、多部件)要素、要素类Q:这些代码里创建要素后会存在XY精度损失的问题,如何解决?A:解决方案是在创建要素过程中指定正确的空间参考。答案来自 geometry-HowtohandlecoordinatesaccuracyinArcGIS-Geog......
  • js 传递汉字 乱码_JavaScript 字符串反转乱码问题解决
    https://blog.csdn.net/weixin_36483301/article/details/113451892emoji表情和非常用字实际解决中文编码问题,可以通过解码解决js中使用decodeURL即可解决......
  • 如何解决Reporting Services目录数据库文件存在的问题
    如何解决ReportingServices目录数据库文件存在的问题浏览:1686|更新:2022-12-0411:211,自检时提示“ReportingServices目录数据库文件存在”失败,“ReportingServices目录临时数据库文件存在”失败。2,打开SQLServer数据库的安装目录,例如:C:\ProgramFiles(x86)\M......