JAVA登录校验

实现登录

    @PostMapping("login")
    public Result login(@RequestBody TbUser user){
        //第一步肯定是先去数据库里查看这个用户是否存在
        TbUser userAdmin = userDao.selectUser(user.getUserName(),user.getUserPassword());
        //第二步,判断不为空的话,就把想封装的信息放到Map集合里面
        if(userAdmin != null){
            //自定义信息
            Map<String , Object> claims = new HashMap<>();
            claims.put("id", userAdmin.getId());
            claims.put("userName",userAdmin.getUserName());
            claims.put("userPassword",userAdmin.getUserPassword());
            //使用JWT工具类,生成身份令牌
            String token = JwtUtils.generateJwt(claims);
            //然后返回给前端
            return Result.ok(token);
        }
        return Result.ok("账号密码错误");
    }

JWT工具类

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;
import java.util.Map;

public class JwtUtils {


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

    /**
     * 生成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;
    }
}

        到这里,登录的操作算是完成了,但是只有登录,没有登录拦截,登录就只算是空有虚表,登录就没有了任何意义

登录拦截

Filter过滤器

        登录拦截我这里选用的是Filter过滤器,我们先看一下过滤器的执行流程

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

在放行后访问完 web 资源之后还会回到过滤器当中,回到过滤器之后如有需求还可以执行放行之后的逻辑,放行之后的逻辑我们写在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 销毁方法执行了");
    }
}

        执行流程我们搞清楚之后,接下来再来介绍一下过滤器的拦截路径,Filter可以根据需求,配置不同的拦截资源路径:

拦截路径urlPatterns值含义
拦截具体路径/login只有访问 /login 路径时,才会被拦截
目录拦截/emps/*访问/emps下的所有资源,都会被拦截

拦截所有

/*访问所有资源,都会被拦截

 过滤器链

        什么是过滤器链呢?所谓过滤器链指的是在一个web应用程序当中,可以配置多个过滤器,多个过滤器就形成了一个过滤器链。

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

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

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

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

登录校验过滤器

  • 要进入到后台管理系统,我们必须先完成登录操作,此时就需要访问登录接口login。

  • 登录成功之后,我们会在服务端生成一个JWT令牌,并且把JWT令牌返回给前端,前端会将JWT令牌存储下来。

  • 在后续的每一次请求当中,都会将JWT令牌携带到服务端,请求到达服务端之后,要想去访问对应的业务功能,此时我们必须先要校验令牌的有效性。

  • 对于校验令牌的这一块操作,我们使用登录校验的过滤器,在过滤器当中来校验令牌的有效性。如果令牌是无效的,就响应一个错误的信息,也不会再去放行访问对应的资源了。如果令牌存在,并且它是有效的,此时就会放行去访问对应的web资源,执行相应的业务操作。

登录验证的流程

代码实现

        

import lombok.Data;

import java.io.Serializable;

@Data
public class Result implements Serializable {
    private int code;
    private String msg;
    private Object data = "";

    public Result() {
    }

    public Result(int code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public Result(String msg, Object data) {
        this.code = 0;
        this.msg = msg;
        this.data = data;
    }

    public Result(Object data) {
        this.code = 0;
        this.msg = "success";
        this.data = data;
    }

    public static Result ok() {
        return new Result(0, "success", "");
    }

    public static Result ok(Object obj) {
        return new Result(0, "success", obj);
    }

    public static Result fail(BusinessStatus businessStatus) {
        return fail(businessStatus, businessStatus.getMessage());
    }

    public static Result notLogin(Object obj){
        return new Result(BusinessStatus.NOT_LOGIN.getCode(), BusinessStatus.NOT_LOGIN.getMessage(), obj);
    }

    public static Result fail(BusinessStatus businessStatus, String msg) {
        Result result = new Result();
        result.setCode(businessStatus.getCode());
        result.setMsg(msg);
        return result;
    }



}


public enum BusinessStatus {
    /**
     * 请求成功
     */
    OK(0, "success"),

    /**
     * 未注册
     */
    NOT_REGISTER(400, "未注册"),

    /**
     * 未注册
     */
    NOT_FORBIDDEN(400, "用户已被禁用"),

    /**
     * 未登录或已过期
     */
    NOT_LOGIN(401, "未登录或已过期"),

    /**
     * 管理员 - 账号密码错误
     */
    ADMIN_PASSWORD(402, "账号密码错误"),

    /**
     * 缺少参数
     */
    REQUIRE_PARAM(403, "缺少参数"),

    /**
     * 无访问权限
     */
    NO_PERMISSION(404, "无访问权限"),

    /**
     * 内容存在敏感或非法内容
     */
    RISKY_CONTENT(405, "内容存在敏感或非法内容"),

    /**
     * 验证码错误
     */
    ADMIN_CODE(406, "验证码错误"),

    /**
     * 验证码超时timestamp
     */
    ADMIN_TIMESTAMP(407, "验证码超时"),

    /**
     * 未知错误
     */
    UNKNOWN(500, "未知错误"),


    /**
     * 操作失败
     */
    FAIL(500, "操作失败"),

    /**
     * 资源不存在
     */
    RESOURCE_NOT_EXISTS(501, "资源不存在"),

    /**
     * 资源已存在
     */
    RESOURCE_HAS_EXISTS(502, "资源已存在"),

    /**
     * 需要完善姓名
     */
    REQUIRE_NAME(503, "需要完善姓名");


    private Integer code;
    private String message;

    BusinessStatus(Integer code, String message) {
        this.code = code;
        this.message = message;
    }

    public Integer getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }

    /**
     * 根据状态码查询错误信息
     *
     * @param code 状态码
     * @return message 错误信息
     */
    public static String getMessage(int code) {
        for (BusinessStatus status : values()) {
            if (status.getCode().equals(code)) {
                return status.getMessage();
            }
        }
        return null;
    }
}
import com.alibaba.fastjson.JSONObject;

import lombok.extern.slf4j.Slf4j;

import org.springframework.util.StringUtils;


import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Slf4j
@WebFilter(urlPatterns = "/*") //拦截所有请求
public class LoginCheckFilter implements Filter {


    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        //前置:强制转换为http协议的请求对象、响应对象 (转换原因:要使用子类中特有方法)
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        //1.获取请求url
        String url = request.getRequestURL().toString();
        log.info("请求路径:{}", url); //请求路径:http://localhost:8080/login


        //2.判断请求url中是否包含login,如果包含,说明是登录操作,放行
        if(url.contains("/login")){
            chain.doFilter(request, response);//放行请求
            return;//结束当前方法的执行
        }


        //3.获取请求头中的令牌(token)
        String token = request.getHeader("token");
        log.info("从请求头中获取的令牌:{}",token);


        //4.判断令牌是否存在,如果不存在,返回错误结果(未登录)
        if(!StringUtils.hasLength(token)){
            log.info("Token不存在");

            Result responseResult = Result.notLogin("请先登录,再操作系统");
            //把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)
            String json = JSONObject.toJSONString(responseResult);
            response.setContentType("application/json;charset=utf-8");
            //响应
            response.getWriter().write(json);

            return;
        }

        //5.解析token,如果解析失败,返回错误结果(未登录)
        try {
            JwtUtils.parseJWT(token);
        }catch (Exception e){
            log.info("令牌解析失败!");

            Result responseResult = Result.notLogin("请先登录,再操作系统");
            //把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)
            String json = JSONObject.toJSONString(responseResult);
            response.setContentType("application/json;charset=utf-8");
            //响应
            response.getWriter().write(json);

            return;
        }


        //6.放行
        chain.doFilter(request, response);

    }
}

以上就是登录验证的代码流程了

此篇文章大量借鉴于https://www.cnblogs.com/shawncs/p/17927620.html#10.%20%E7%99%BB%E5%BD%95%E6%A0%A1%E9%AA%8C-Filter-%E8%AF%A6%E8%A7%A3%EF%BC%88%E6%89%A7%E8%A1%8C%E6%B5%81%E7%A8%8B-%E6%8B%A6%E6%88%AA%E8%B7%AF%E5%BE%84%EF%BC%89

 这个链接里写的是最详细的,想认真学过滤器和拦截器的,可以去看看这个文章

  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咸鱼的动力

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值