使用AOP切面编程实现登录拦截
1. 首先实现一个登录注册功能
以下代码仅供参考
- 控制层
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate 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);}
}
- 业务层
@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@Resourceprivate 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);}@Overridepublic 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层
@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 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类
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface GlobalInterceptor {/*** 校验登录** @return*/boolean checkLogin() default true;/*** 校验管理员** @return*/boolean checkAdmin() default false;
}
- GlobalOperationAspect类
@Component("operationAspect")
@Aspect
public class GlobalOperationAspect {@Resourceprivate RedisTemplate<String,String> redisTemplate;@Resourceprivate 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) {// 校验是否为管理员操作权限// 后续处理}}
}
接下来只需要在需要拦截的接口处添加自定义注解就可以了
如:
@RestController
@RequestMapping("/test")
public class TestController {@GlobalInterceptor@GetMapping("/test")public String test() {return "ok";}
}
4. 测试
-
首先登录后获取用户token
-
再将token放入请求头中
一个AOP切面编程实现的登录拦截就实现了