SpringBoot中使用AOP切面编程实现登录拦截

使用AOP切面编程实现登录拦截

1. 首先实现一个登录注册功能

以下代码仅供参考

  • 控制层
java 复制代码
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;
    @PostMapping("/register")
    public Result register(@RequestBody UserDto userDto) {
        userService.addUser(userDto);
        return Result.success("注册成功");
    }

    @PostMapping("/login")
    public Result<UserLoginVo> login(@RequestBody UserDto userDto) {
        UserLoginVo userLoginVo = userService.login(userDto);
        return Result.success(userLoginVo);
    }
}
  • 业务层
java 复制代码
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;
    @Resource
    private RedisTemplate<String,String> redisTemplate;
    /**
     * 新增用户/注册
     * @param userDto
     */
    public void addUser(UserDto userDto) {
        User user = userMapper.selectByUserName(userDto.getUsername());
        if (user != null) {
            throw new BusinessException(ResponseCodeEnum.CODE_601);
        }
        user = new User();
        BeanUtils.copyProperties(userDto, user);
        user.setCreateTime(new Date());
        user.setLoginTime(new Date());
        userMapper.insert(user);
    }

    @Override
    public UserLoginVo login(UserDto userDto) {
        User user = userMapper.selectByUserNameAndPassword(userDto.getUsername(),userDto.getPassword());
        if (user == null) {
            throw new BusinessException("用户名或密码错误");
        }
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set("loginDemo:user:token:" + token, user.getId().toString());
        UserLoginVo userLoginVo = new UserLoginVo();
        userLoginVo.setUser(user);
        userLoginVo.setToken(token);
        return userLoginVo;
    }
}
  • mapper层
java 复制代码
@Mapper
public interface UserMapper extends BaseMapper<User>{


    void addUser(User user);
    
    @Select("select * from user where username = #{username}")
    User selectByUserName(String username);

    User selectByUserNameAndPassword(String username,String password);
}
  • UserMapper.xml
xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.kkk.mapper.UserMapper">

    <insert id="addUser">
        INSERT INTO user (
            username,
            password,
            email
        ) VALUES (
                     #{username},
                     #{password},
                     #{email}
                 )
    </insert>
    <select id="selectByUserNameAndPassword" resultType="com.kkk.domain.entity.User">
        select * from user
        <where>
            <if test="username != null and username != ''">
                and user.username = #{username}
            </if>
            <if test="password != null and password != ''">
                and user.password = #{password}
            </if>
        </where>
    </select>

</mapper>

以上代码仅供参考,具体逻辑可以根据自己的业务来实现

2. 补充介绍

以上提供的示例代码逻辑大致为用户登录后根据UUID生成一个token,接着将token作为唯一标识键存入redis缓存中,值为用户id,之后可以根据用户请求头中的token去redis中获取用户id,当然你也可以根据自己的实际需求来。

3.AOP切面编程实现登录拦截校验

首先目录结构如图所示

  • GlobalInterceptor类
java 复制代码
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface GlobalInterceptor {

    /**
     * 校验登录
     *
     * @return
     */
    boolean checkLogin() default true;

    /**
     * 校验管理员
     *
     * @return
     */
    boolean checkAdmin() default false;
}
  • GlobalOperationAspect类
java 复制代码
@Component("operationAspect")
@Aspect
public class GlobalOperationAspect {


    @Resource
    private RedisTemplate<String,String> redisTemplate;
    @Resource
    private UserMapper userMapper;

    private static Logger logger = LoggerFactory.getLogger(GlobalOperationAspect.class);


    @Before("@annotation(com.kkk.annotation.GlobalInterceptor)")
    public void interceptorDo(JoinPoint point) {
        try {
            Method method = ((MethodSignature) point.getSignature()).getMethod();
            GlobalInterceptor interceptor = method.getAnnotation(GlobalInterceptor.class);
            if (null == interceptor) {
                return;
            }
            /**
             * 校验登录
             */
            if (interceptor.checkLogin() || interceptor.checkAdmin()) {
                checkLogin(interceptor.checkAdmin());
            }
        } catch (BusinessException e) {
            logger.error("全局拦截器异常", e);
            throw e;
        } catch (Exception e) {
            logger.error("全局拦截器异常", e);
            throw new BusinessException(ResponseCodeEnum.CODE_500);
        } catch (Throwable e) {
            logger.error("全局拦截器异常", e);
            throw new BusinessException(ResponseCodeEnum.CODE_500);
        }
    }

    //校验登录
    private void checkLogin(Boolean checkAdmin) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token = request.getHeader("token");
        String value = redisTemplate.opsForValue().get("loginDemo:user:token:"+token);
        if (value == null) {
            throw new BusinessException("登录超时");
        }
        Long userId = Long.valueOf(value);
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException("请求参数错误,请联系管理员");
        }
        if (checkAdmin) {
            // 校验是否为管理员操作权限
            // 后续处理
        }
    }
}

接下来只需要在需要拦截的接口处添加自定义注解就可以了

如:

java 复制代码
@RestController
@RequestMapping("/test")
public class TestController {

    @GlobalInterceptor
    @GetMapping("/test")
    public String test() {
        return "ok";
    }
}

4. 测试

  • 首先登录后获取用户token

  • 再将token放入请求头中

一个AOP切面编程实现的登录拦截就实现了

相关推荐
哦虎!8 小时前
【JavaEE】网络初识
java
for_ever_love__8 小时前
MySQL ORDER BY 排序优化:从 Using filesort 到索引有序扫描(含双路 / 单路排序原理)
java·mysql·优化·存储·by·order·filesort
我是人✓9 小时前
Java文件上传三方式对比:从传统到SpringBoot
java·开发语言
欣栀♡9 小时前
JVM 频繁 Full GC 先看日志括号里的 cause,jstat 的 FGC 在 JDK 8 上会骗人
java·jvm
IT研究室10 小时前
最新计算机毕业设计选题推荐-基于spring boot的葡萄酒文化宣传网站-网站-文档指导-Java-springboot
java·spring boot·课程设计
慧都小项10 小时前
MyEclipse 中创建和测试 JAX-RS REST 接口:从项目配置到 REST Explorer
java·restful·myeclipse·jax-rs
Wang's Blog10 小时前
Java 项目实战: 交友项目 - 入门案例:编写 Dubbo 服务提供者
java·dubbo·交友
秋饼10 小时前
Spring AI 2.0 结构化输出企业级实战:从 BeanOutputConverter 源码到生产级解析容错
java·ai·技术分享·后端开发
摇滚侠10 小时前
《计算机是如何工作的:人人都能懂的计算机软硬件工作原理》第 9 章 机器码与汇编语言 阅读笔记 9
java·开发语言·笔记
Cc.Y10 小时前
Java零基础入门:深入Java核心:文件IO与序列化全解
java·开发语言·python