JavaWeb基础知识-登录效验-spring事务-AOP(二)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 2.JWT令牌全称:JSON Web Token (https:/ljwt.io/)定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。组成:第一部分:Header(头),记录令牌类型、签名算法等。例如: {“alg”:“HS256” ,“type” :“JWT”}第二部分: Payload(有效载荷),携带一些自定义信息、默认信息等。例如:{“id”.“1” ,“username”:“Tom”}第三部分: Signature(签名),防止Token被篡改、确保安全性。将header、 payload,并加入指定秘钥

登录功能f2cae24d585f4800b4b294d6dabcaac9.png登录校验(重点)

46a702f674fd4ff698029056a50e31b4.png


1.会话技术


e5a3ba172a074705a4bf46c23308cceb.png

image.png

2.JWT令牌

全称:JSON Web Token (https:/ljwt.io/)
定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在
,这些信息是可靠的。

组成:

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

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

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

a15db76f555b4ee0b77ea851b3694f0a.png

0c49db5287de41919ab4510b7a31a6d3.png

引入jwt依赖
< dependency>
< groupld>io.jsonwebtoken< /groupld>
< artifactld>jjwt< /artifactld>
< version>0.9.1< /version>
< /dependency>

测试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))//有效期为一个小时
        .compact();
        System.out.println(jwt);
    }
//解析jwt
    @Test
public void testParseJwt(){
      Claims claims = Jwts.parser()
       .setSigningKey("itheima")
       .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoidG9tIiwiaWQiOjEsImV4cCI6MTY4MDUyODU0MH0.kb92jCCJnV9mXbn6qz_3yNzLzO5zzDTxn4Cq4ysCSd0")
       .getBody();
    System.out.println(claims);
}

JWT校验时使用的签名秘钥,必须和生成JWT令牌时使用的秘钥是配套的。
如果JWT令牌解析校验时报错,则说明JWT令牌被篡改或失效了,令牌非法。

3.过滤器Filter

78bb3e45ece14ff392259f71513dcb8b.png


image.png

放行后访问对应资源,资源访问完成后,还会回到Filter中。
回到Filter中,执行的是放行后的逻辑。


f8614593454246a3aed6f9b290bddda6.png


25bca5a0cb2740f195d4fcd7b2eeb71b.png

e0eebfb8a7b64676b494407a0007acba.png


代码实现在Filter包下创建一个LoginCheckFilter 类

@Slf4j
@WebFilter(urlPatterns = "/*")
public class LoginCheckFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req=(HttpServletRequest) servletRequest;
        HttpServletResponse resp=(HttpServletResponse) servletResponse;
        //1.获取请求url
        String url= req.getRequestURI().toString();
        log.info("请求路径的url:{}",url);
        //2.判断请求url是否包含login 如果包含 说明是登录操作 放行
  if (url.contains("login")){
      log.info("这是登录操作 放行");
      filterChain.doFilter(servletRequest, servletResponse);
     return;
  }
        //3.获取请求头中的令牌(token)
        String jwt = req.getHeader("token");
        //4,判断令牌是否存在 如果不存在 返回错误结果(未登录)
if (!StringUtils.hasLength(jwt)){
    log.info("请求头token为空,返回未登录信息");
    Result error=Result.error("NOT_LOGIN");
     //手动转换 对象json 引入阿里巴巴fastjson依赖  
     //<!--fastJson-->
       // <dependency>
          //  <groupId>com.alibaba</groupId>
          //  <artifactId>fastjson</artifactId>
         //   <version>1.2.76</version>
       // </dependency>
    String notlogin = JSONObject.toJSONString(error);
    resp.getWriter().write(notlogin);
    return;
}
        //5.解析token 如果解析失败 返回错误结果(未登录)
        try {
            JwtUtils.parseJWT(jwt);
        }catch (Exception e){//解析失败
            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("令牌合法 放行");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}
4.拦截器Interceptor


4394b114dc7e44e3a505ca139f495d3b.png


eeb09e4fac0f460ca24727c1e4eab756.png


image.png


image.png

实现代码新建一个LoginCheckInterceptor类

@Component
@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor {
    @Override//目标方法运行前 执行 返回true 放行 flase 不放行
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1.获取请求url
        String url= request.getRequestURI().toString();
        log.info("请求路径的url:{}",url);
        //2.判断请求url是否包含login 如果包含 说明是登录操作 放行
        if (url.contains("login")){
            log.info("这是登录操作 放行");
            return true;
        }
        //3.获取请求头中的令牌(token)
        String jwt = request.getHeader("token");
        //4,判断令牌是否存在 如果不存在 返回错误结果(未登录)
        if (!StringUtils.hasLength(jwt)){
            log.info("请求头token为空,返回未登录信息");
            Result error=Result.error("NOT_LOGIN");
            //手动转换 对象json 阿里巴巴fastjson
            String notlogin = JSONObject.toJSONString(error);
            response.getWriter().write(notlogin);
            return false;
        }
        //5.解析token 如果解析失败 返回错误结果(未登录)
        try {
            JwtUtils.parseJWT(jwt);
        }catch (Exception e){//解析失败
            e.printStackTrace();
            log.info("解析令牌失败,返回未登录错误信息");
            Result error=Result.error("NOT_LOGIN");
            //手动转换 对象json 阿里巴巴fastjson
            String notlogin = JSONObject.toJSONString(error);
            response.getWriter().write(notlogin);
            return false;
        }
        //6.放行
        log.info("令牌合法 放行");
        return true;
    }
    @Override//目标方法执行后运行
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }
    @Override//视图渲染完毕后运行 最后运行
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

新建一个配置类WebMvcConfigurer

@Configuration//配置类
public class WebMvcConfigurer implements org.springframework.web.servlet.config.annotation.WebMvcConfigurer {
    @Autowired
    private LoginCheckInterceptor loginCheckInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");
    }
}

异常处理


aa88676e01b44bdea866c4237f461023.png

spring事务管理

1.事务回顾


8e1ccf8fb4a4450ca68361663e805b07.png

2.Spring事务管理

image.pngspring事务管理日志
logging:
level:
org.springframework.jdbc.support.JdbcTransactionManager: debug

3.事务进阶


image.png

2.propagation


image.png

REQUIRED:大部分情况下都是用该传播行为即可。
REQUIRES_NEWN:当我们不希望事务之间相互影响时,可以使用该传播行为。比如:下订单前需要记录日志,不论订单保存成功与否,都需要保证日志记录能够记录成功

AOP基础

1.AOP概述

AOP:Aspect Orie

nted Programming(面向切面编程、面向方面编程),其实就是面向特定方法编程。
动态代理是面向切面编程最主流的实现。而$pringAOP是Spring框架的高级技术,旨在管理bean对象的过程中,主要通过底层的动态代理机制,对特定的方法进行编程。

2.AOP快速入门


image.png

image.png

3.AOP核心概念


image.png

AOP进阶


image.png


5c042468ef5a45ac9513047f332414fe.png


image.pngimage.png

书写建议

所有业务方法名在命名时尽量规范,方便切入点表达式快速匹配、如:查询类方法都是find开头,更新类方法都是update开头。

描述切入点方法通常基于接口描述,而不是直接描述实现类,增强拓展性。

在满足业务需要的前提下,尽量缩小切入点的匹配范围。

如:包名匹配尽量不使用…使用*匹配单个包。

image.png


image.png

image.png

创建实体类OperateLog

@Data
@NoArgsConstructor
@AllArgsConstructor
public class OperateLog {
    private Integer id; //ID
    private Integer operateUser; //操作人ID
    private LocalDateTime operateTime; //操作时间
    private String className; //操作类名
    private String methodName; //操作方法名
    private String methodParams; //操作方法参数
    private String returnValue; //操作方法返回值
    private Long costTime; //操作耗时
}

创建OperateLogMapper接口

@Mapper
public interface OperateLogMapper {
    //插入日志数据
    @Insert("insert into operate_log (operate_user, operate_time, class_name, method_name, method_params, return_value, cost_time) " +
            "values (#{operateUser}, #{operateTime}, #{className}, #{methodName}, #{methodParams}, #{returnValue}, #{costTime});")
    public void insert(OperateLog log);
}

创建Log注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Log {
}

创建LogAspect类

@Component
@Aspect//切面类
@Slf4j
public class LogAspect {
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private OperateLogMapper operateLogMapper;
    @Around("@annotation(com.itheima.anno.Log)")
public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable {
        //操作人id
    //获取请求头中的wjt令牌 解析令牌
        String jwt = request.getHeader("token");
        Claims claims = JwtUtils.parseJWT(jwt);
Integer operateUser=(Integer) claims.get("id");
        //操作时间
        LocalDateTime operateTime=LocalDateTime.now();
        //操作类名
String className=joinPoint.getTarget().getClass().getName();
        //操作方法名
        String methodName = joinPoint.getSignature().getName();
        //操作方法参数
        Object[] args = joinPoint.getArgs();
        String methodParams= Arrays.toString(args);
        //方法返回值
        //调用原始目标方法时间
        long begin = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long end = System.currentTimeMillis();
        String returnValue = JSONObject.toJSONString(result);
        //操作耗时
long costTime=end-begin;
        //调用原始目标方法
        //记录操作日志
        OperateLog operateLog=new OperateLog(null,operateUser,operateTime,className,methodName,methodParams,returnValue,costTime);
operateLogMapper.insert(operateLog);
log.info("aop操作日志{}",operateLog);
        return  result;
    }
}

最后在增删改方法上加上@Log注解

美好的一天,到此结束,下次继续努力!

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
2月前
|
监控 安全 Java
Spring AOP实现原理
本内容主要介绍了Spring AOP的核心概念、实现机制及代理生成流程。涵盖切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)等关键概念,解析了JDK动态代理与CGLIB代理的原理及对比,并深入探讨了通知执行链路和责任链模式的应用。同时,详细分析了AspectJ注解驱动的AOP解析过程,包括切面识别、切点表达式匹配及通知适配为Advice的机制,帮助理解Spring AOP的工作原理与实现细节。
|
4月前
|
Java Spring
Spring中事务失效的场景
因为Spring事务是基于代理来实现的,所以某个加了@Transactional的⽅法只有是被代理对象调⽤时, 那么这个注解才会⽣效 , 如果使用的是被代理对象调用, 那么@Transactional会失效 同时如果某个⽅法是private的,那么@Transactional也会失效,因为底层cglib是基于⽗⼦类来实现 的,⼦类是不能重载⽗类的private⽅法的,所以⽆法很好的利⽤代理,也会导致@Transactianal失效 如果在业务中对异常进行了捕获处理 , 出现异常后Spring框架无法感知到异常, @Transactional也会失效
|
3月前
|
存储 Java 数据库
Spring Boot 注册登录系统:问题总结与优化实践
在Spring Boot开发中,注册登录模块常面临数据库设计、密码加密、权限配置及用户体验等问题。本文以便利店销售系统为例,详细解析四大类问题:数据库字段约束(如默认值缺失)、密码加密(明文存储风险)、Spring Security配置(路径权限不当)以及表单交互(数据丢失与提示不足)。通过优化数据库结构、引入BCrypt加密、完善安全配置和改进用户交互,提供了一套全面的解决方案,助力开发者构建更 robust 的系统。
111 0
|
4月前
|
Java 关系型数据库 数据库
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——常见问题总结
本文总结了Spring Boot中使用事务的常见问题,虽然通过`@Transactional`注解可以轻松实现事务管理,但在实际项目中仍有许多潜在坑点。文章详细分析了三个典型问题:1) 异常未被捕获导致事务未回滚,需明确指定`rollbackFor`属性;2) 异常被try-catch“吃掉”,应避免在事务方法中直接处理异常;3) 事务范围与锁范围不一致引发并发问题,建议调整锁策略以覆盖事务范围。这些问题看似简单,但一旦发生,排查难度较大,因此开发时需格外留意。最后,文章提供了课程源代码下载地址,供读者实践参考。
83 0
|
4月前
|
Java 关系型数据库 数据库
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——Spring Boot 事务配置
本文介绍了 Spring Boot 中的事务配置与使用方法。首先需要导入 MySQL 依赖,Spring Boot 会自动注入 `DataSourceTransactionManager`,无需额外配置即可通过 `@Transactional` 注解实现事务管理。接着通过创建一个用户插入功能的示例,展示了如何在 Service 层手动抛出异常以测试事务回滚机制。测试结果表明,数据库中未新增记录,证明事务已成功回滚。此过程简单高效,适合日常开发需求。
197 0
|
4月前
|
Java 数据库 微服务
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——事务相关
本文介绍Spring Boot事务配置管理,阐述事务在企业应用开发中的重要性。事务确保数据操作可靠,任一异常均可回滚至初始状态,如转账、购票等场景需全流程执行成功才算完成。同时,事务管理在Spring Boot的service层广泛应用,但根据实际需求也可能存在无需事务的情况,例如独立数据插入操作。
56 0
|
2月前
|
人工智能 Java 数据库连接
Spring事务失效场景
本文深入探讨了Spring框架中事务管理可能失效的几种常见场景及解决方案,包括事务方法访问级别不当、方法内部自调用、错误的异常处理、事务管理器或数据源配置错误、数据库不支持事务以及不合理的事务传播行为或隔离级别。通过合理配置和正确使用`@Transactional`注解,开发者可以有效避免这些问题,确保应用的数据一致性和完整性。
114 10
|
1月前
|
Java 关系型数据库 MySQL
【Spring】【事务】初学者直呼学会了的Spring事务入门
本文深入解析了Spring事务的核心概念与使用方法。Spring事务是一种数据库事务管理机制,通过确保操作的原子性、一致性、隔离性和持久性(ACID),维护数据完整性。文章详细讲解了声明式事务(@Transactional注解)和编程式事务(TransactionTemplate、PlatformTransactionManager)的区别与用法,并探讨了事务传播行为(如REQUIRED、REQUIRES_NEW等)及隔离级别(如READ_COMMITTED、REPEATABLE_READ)。
116 1
|
4月前
|
SQL Java 数据库连接
Spring中的事务是如何实现的
1. Spring事务底层是基于数据库事务和AOP机制的 2. ⾸先对于使⽤了@Transactional注解的Bean,Spring会创建⼀个代理对象作为Bean 3. 当调⽤代理对象的⽅法时,会先判断该⽅法上是否加了@Transactional注解 4. 如果加了,那么则利⽤事务管理器创建⼀个数据库连接 5. 并且修改数据库连接的autocommit属性为false,禁⽌此连接的⾃动提交,这是实现Spring事务⾮ 常重要的⼀步 6. 然后执⾏当前⽅法,⽅法中会执⾏sql 7. 执⾏完当前⽅法后,如果没有出现异常就直接提交事务 8. 如果出现了异常,并且这个异常是需要回滚的就会回滚事务
|
4月前
|
JavaScript Java 开发者
Spring事务失效,常见的情况有哪些?
本文总结了Spring事务失效的7种常见情况,包括未启用事务管理功能、方法非public类型、数据源未配置事务管理器、自身调用问题、异常类型错误、异常被吞以及业务和事务代码不在同一线程中。同时提供了两种快速定位事务相关Bug的方法:通过查看日志(设置为debug模式)或调试代码(在TransactionInterceptor的invoke方法中设置断点)。文章帮助开发者更好地理解和解决Spring事务中的问题。
131 7

热门文章

最新文章