登录认证校验(JWT令牌,过滤器Filter,拦截器lnterceptor,异常处理)

目录

登录功能

登录校验(重点) 

 会话技术

令牌技术

 JWT生成令牌

 JWT校验

场景:登录认证。

实现统一校验JWT令牌(登录成功标记):

过滤器Filter

​编辑

快速入门:

 详解(执行流程,拦截路径,过滤器链)

过滤器链

场景:登录校验filter

拦截器lnterceptor

 登录校验lnterceptor

异常处理


登录功能

 创建LoginController中:

@Slf4j
@RestController
public class LoginController {

    @Autowired
    private EmpService empService;

    @PostMapping("/login")
    public Result login(@RequestBody Emp emp){
        log.info("员工登录: {}", emp);
        Emp e = empService.login(emp);

        return e !=null?Result.success():Result.error("用户名或者密码错误");

}

 Emp login(Emp emp); 

 @Override
    public Emp login(Emp emp) {
        return empMapper.getByUsernameAndPassword(emp);
    } 

@Select("select * from emp where username = #{username} and password = #{password}")
    Emp getByUsernameAndPassword(Emp emp); 

登录校验(重点) 

 会话技术

会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应。

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

会话跟踪方案:

1.客户端会话跟踪技术:Cookie

2.服务端会话跟踪技术:Session

令牌技术

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

Base64:是一种基于64个可打印字符(A-Z  a-z  0-9  +  /)来表示二进制数据的 编码方式。

 JWT生成令牌

1.在pom.xml中加入依赖

<dependency>    

<groupId>io.jsonwebtoken</groupId>    

<artifactId>jjwt</artifactId>    

<version>0.9.1</version>

</dependency>

2.在单元测试类定义一个测试方法,生成JWT令牌

//@SpringBootTest
class TliasWebManagementApplicationTests {

    /**
     * 生成JWT
     */
    @Test
    public void testGenJwt(){
        Map<String, Object> claims = new HashMap<>();
        claims.put("id",1);
        claims.put("name","tom");

        String jwt = Jwts.builder()
                .signWith(SignatureAlgorithm.HS256, "itheima")//签名算法
                .setClaims(claims) //自定义内容(载荷)
                .setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))//设置有效期为1h
                .compact();//字符串返回值
        System.out.println(jwt);
    }

 JWT校验

    /**
     * 解析JWT
     */
    @Test
    public void testParseJwt(){
        Claims claims = Jwts.parser()
                .setSigningKey("itheima")
                .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoidG9tIiwiaWQiOjEsImV4cCI6MTY3MDQ2NDU0N30.yPLRyiusrlrmWeC4-dhInjFuAghPkmiHSRHd_DTKi9E")
                .getBody();//自定义内容
        System.out.println(claims);
    }
}

注意:JWT校验时使用的签名秘钥,必须和生成JWT令牌时使用的秘钥是配套的。

如果JWT令牌解析校验时报错,则说明 JWT令牌被篡改 或 失效了,令牌非法。

场景:登录认证。

令牌生成:登录成功后,生成令牌,然后返回给前端

令牌校验:在请求到达服务端后,对令牌进行统一拦截,校验。(后续每个请求,都要携带JWT令牌,系统在每次请求处理之前,先校验令牌,通过后,再处理)

登录-生成令牌

1.引入JWT令牌操作工具类。

2.登录完成后,调用工具类生成JWT令牌,并返回。

1.utils下导入JwtUtils工具类

LoginController下:(登录成功,生成令牌,下发令牌)

@Slf4j
@RestController
public class LoginController {

    @Autowired
    private EmpService empService;

    @PostMapping("/login")
    public Result login(@RequestBody Emp emp){
        log.info("员工登录: {}", emp);
        Emp e = empService.login(emp);

       

//登录成功,生成令牌,下发令牌
        if (e != null){
            Map<String, Object> claims = new HashMap<>();
            claims.put("id", e.getId());
            claims.put("name", e.getName());
            claims.put("username", e.getUsername());

            String jwt = JwtUtils.generateJwt(claims); //jwt包含了当前登录的员工信息
            return Result.success(jwt);
        }

       

//登录失败, 返回错误信息
        return Result.error("用户名或密码错误");
    }

}

实现统一校验JWT令牌(登录成功标记):

过滤器Filter

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

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

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

快速入门:

1.定义Filter:定义一个类,实现 Filter 接口,并重写其所有方法。

2.配置Filter:Filter类上加 @WebFilter 注解,配置拦截资源的路径。启动类上加 @ServletComponentScan 开启Servlet组件支持。

filter包下的DemoFiler类:

@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {
    @Override //初始化方法, web服务器启动,创建filter时调用,只调用一次
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init 初始化方法执行了");
    }

    @Override //拦截到请求之后调用, 调用多次
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {  //拦截到请求时,调用该方法,可调用多次
        System.out.println("Demo 拦截到了请求...放行前逻辑");  
        //放行
        chain.doFilter(request,response);

        System.out.println("Demo 拦截到了请求...放行后逻辑");
    }

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

 加注解:

 详解(执行流程,拦截路径,过滤器链)

请求 --> 放行前逻辑 --> 放行 --> 资源 --> 放行后逻辑

过滤器链

一个web应用中,可以配置多个过滤器,这多个过滤器就形成了一个过滤器链。

顺序:注解配置的Filter,执行优先级是按照过滤器类名(字符串)的自然排序确定

一个一个执行

 filter包下的DemoFiler类:

@WebFilter(urlPatterns = "/*")
public class XbcFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("Abc 拦截到了请求...放行前逻辑");
        //放行
        chain.doFilter(request,response);

        System.out.println("Abc 拦截到了请求...放行后逻辑");
    }
}

场景:登录校验filter

访问后台管理系统,先完成登录操作,先访问登录接口login,登录成功之后,在服务端生成一个JWT令牌,并且把JWT令牌返回给前端,前端将其记录下来,在后面请求中,将JWT令牌携带到服务端,要想访问对应功能,先得校验令牌有效性,直接过滤器实现,在过滤器校验令牌有效性

若无效,直接响应错误信息,不会放行去访问,如果存在有效,则会放行,访问对应web资源,执行对应业务操作, 

前端请求服务器,是在请求头当中将令牌携带到服务端的,请求头名字为token

 

在filter下

@Slf4j
@WebFilter(urlPatterns = "/*")
public class LoginCheckFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;

        //1.获取请求url。
        String url = req.getRequestURL().toString();
        log.info("请求的url: {}",url);

        //2.判断请求url中是否包含login,如果包含,说明是登录操作,放行。
        if(url.contains("login")){
            log.info("登录操作, 放行...");
            chain.doFilter(request,response);
            return;
        }

        //3.获取请求头中的令牌(token)。
        String jwt = req.getHeader("token");

        //4.判断令牌是否存在,如果不存在,返回错误结果(未登录)。
        if(!StringUtils.hasLength(jwt)){  //字符串为null或空串
            log.info("请求头token为空,返回未登录的信息");
            Result error = Result.error("NOT_LOGIN");
            //手动转换 对象--json --------> 阿里巴巴fastJSON
            String notLogin = JSONObject.toJSONString(error);
            resp.getWriter().write(notLogin);
            return;
        }

        //5.解析token,如果解析失败,返回错误结果(未登录)。
        try {
            JwtUtils.parseJWT(jwt);
        } catch (Exception e) {//jwt解析失败
            e.printStackTrace();
            log.info("解析令牌失败, 返回未登录错误信息");
            Result error = Result.error("NOT_LOGIN");
            //手动转换 对象--json --------> 阿里巴巴fastJSON
            String notLogin = JSONObject.toJSONString(error);
            resp.getWriter().write(notLogin);
            return;
        }

        //6.放行。
        log.info("令牌合法, 放行");
        chain.doFilter(request, response);

    }
}

 

 

 

拦截器lnterceptor

是一种动态拦截方法调用的机制,类似于过滤器。Spring框架中提供的,用来动态拦截控制器方法的执行

作用:拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码。

 

入门

1.定义拦截器,实现HandlerInterceptor接口,并重写其所有方法。

2.注册拦截器

interceptor下的LoginCheckInterceptor.java:(ctrl+o:重写方法)

 config下的WebConfig:(配置类) 

 详解(拦截路径,执行流程)

 

 Filter与interceptor

区别:接口规范不同:过滤器需要实现Filter接口,而拦截器需要实现HandlerInterceptor接口。

拦截范围不同:过滤器Filter会拦截所有的资源,而Interceptor只会拦截Spring环境中的资源。

 登录校验lnterceptor

package com.itheima.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.itheima.pojo.Result;
import com.itheima.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
    @Override //目标资源方法运行前运行, 返回true: 放行, 放回false, 不放行
    public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
        //1.获取请求url。
        String url = req.getRequestURL().toString();
        log.info("请求的url: {}",url);

        //2.判断请求url中是否包含login,如果包含,说明是登录操作,放行。
        if(url.contains("login")){
            log.info("登录操作, 放行...");
            return true;
        }

        //3.获取请求头中的令牌(token)。
        String jwt = req.getHeader("token");

        //4.判断令牌是否存在,如果不存在,返回错误结果(未登录)。
        if(!StringUtils.hasLength(jwt)){
            log.info("请求头token为空,返回未登录的信息");
            Result error = Result.error("NOT_LOGIN");
            //手动转换 对象--json --------> 阿里巴巴fastJSON
            String notLogin = JSONObject.toJSONString(error);
            resp.getWriter().write(notLogin);
            return false;
        }

        //5.解析token,如果解析失败,返回错误结果(未登录)。
        try {
            JwtUtils.parseJWT(jwt);
        } catch (Exception e) {//jwt解析失败
            e.printStackTrace();
            log.info("解析令牌失败, 返回未登录错误信息");
            Result error = Result.error("NOT_LOGIN");
            //手动转换 对象--json --------> 阿里巴巴fastJSON
            String notLogin = JSONObject.toJSONString(error);
            resp.getWriter().write(notLogin);
            return false;
        }

        //6.放行。
        log.info("令牌合法, 放行");
        return true;
    }

    @Override //目标资源方法运行后运行
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle ...");
    }

    @Override //视图渲染完毕后运行, 最后运行
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion...");
    }
}

异常处理

全局异常处理器

exception包下的GlobalExceptionHandler:

 注解:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 中使用 JWT 实现登录拦截器的步骤如下: 1. 首先,你需要引入所需的依赖。可以使用 Maven 或 Gradle 来管理依赖项,以下是使用 Maven 的示例: ```xml <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.2</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.2</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.2</version> <scope>runtime</scope> </dependency> ``` 2. 创建一个 JWTUtil 工具类,用于生成和解析 JWT。可以使用 jjwt 库来实现这些功能。以下是一个示例: ```java import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import java.util.Date; public class JWTUtil { private static final long EXPIRATION_TIME = 864_000_000; // 10 days private static final String SECRET_KEY = "yourSecretKey"; public static String generateToken(String username) { Date now = new Date(); Date expiryDate = new Date(now.getTime() + EXPIRATION_TIME); return Jwts.builder() .setSubject(username) .setIssuedAt(now) .setExpiration(expiryDate) .signWith(SignatureAlgorithm.HS512, SECRET_KEY) .compact(); } public static String getUsernameFromToken(String token) { Claims claims = Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token) .getBody(); return claims.getSubject(); } } ``` 3. 创建一个自定义的登录拦截器类,用于验证 JWT。可以实现 `HandlerInterceptor` 接口,并在 `preHandle()` 方法中进行登录验证。以下是一个示例: ```java import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class JwtInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization"); if (token != null && token.startsWith("Bearer ")) { token = token.substring(7); String username = JWTUtil.getUsernameFromToken(token); // 进行用户验证逻辑 return true; // 放行请求 } response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return false; // 拦截请求 } } ``` 4. 在 Spring Boot 中配置拦截器。在你的配置类中,使用 `addInterceptors()` 方法将拦截器添加到应用程序中。以下是一个示例: ```java 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 WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new JwtInterceptor()) .addPathPatterns("/api/**") // 拦截指定路径的请求 .excludePathPatterns("/api/login"); // 排除登录接口 } } ``` 以上是使用 JWT 实现登录拦截器的基本步骤。你可以根据自己的实际需求进行相应的调整和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值