Spring Boot+Redis通过获取本机Mac地址实现异地登录检测

1.前言

        需要实现类似QQ等账号异地登陆设备的检测有诸多方法,本例使用比较常用的一种方法就是获取Mac地址后保存到Redis当中,当在不同的设备登录时会检测当机的Mac地址与保存在Redis中的Mac地址是否匹配,若不匹配则拒绝登录。

那么,正片开始!!!

2.Spring Boot项目创建

        

这是整个项目的大致目录,各位可以参考一下,但不需要完全相同

等待IDEA解析完成后即可开始编码

3.编码

首先在application.properties中进行配置

spring.datasource.url=jdbc:mysql://localhost:3306/你的数据库名称?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=PRC&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=123456
spring.banner.location=classpath:1.txt
spring.servlet.multipart.enabled=true

#mybatis相关配置
mybatis.mapperLocations=classpath:mapper/*.xml
mybatis.type-aliases-package=springboot_olmusic.pojo
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

#Redis相关配置
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
spring.redis.timeout=30000
spring.redis.database=0
spring.redis.pool.max-wait=-1

在pojo下创建名为User的实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private Integer uid;
    private String userCode;
    private String password;
}

在src/mapper下创建名为UserMapper的接口文件

import org.apache.ibatis.annotations.Mapper;
import springboot_olmusic.pojo.User;

@Mapper
public interface UserMapper {

    User selectUserCodeBypwd(String userCode);
}

在resource/mapper中创建xml文件

<?xml version = "1.0" encoding = "UTF-8"?>
<!DOCTYPE mapper PUBLIC
        "-//mybatis.org//DTD com.example.Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="你的接口文件地址">

    <select id="selectUserCodeBypwd" resultType="springboot_olmusic.pojo.User">
        select * from oluser
        where userCode = #{userCode}
    </select>
</mapper>

服务层代码:

import cn.hutool.json.JSONUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import springboot_olmusic.mapper.UserMapper;
import springboot_olmusic.pojo.User;
import springboot_olmusic.utils.*;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.Objects;

@Service
public class UserService {

    MacAddressUtil macAddressUtil = new MacAddressUtil();

    @Resource
    private UserMapper userMapper;

    @Resource
    private RedisTemplate redisTemplate;

    public static long USER_TIME = 5 * 60 * 1000;

    private static final String USER_KEY = "user:";

    private static final String MACAddress = "macAddress:";

    public ResponseResult login(String userCode, String password){
        Object userObj = null;
        if (Objects.isNull(userCode) || Objects.isNull(password)
                || userCode == "" || password == ""){
            return new ResponseResult(StatusCode.USER_PASSWORD_NULL, "账号或密码不能为空");
        }

        userObj = redisTemplate.opsForValue().get(USER_KEY + userCode);

        if (userObj != null) {
            String obj = String.valueOf(redisTemplate.opsForValue().get(MACAddress + userCode));
            System.out.println("aaaaaaaaa:" + obj);
            String macAddress = macAddressUtil.getMacAddress();
            if (!obj.equals(macAddress)){
                return new ResponseResult(StatusCode.DATA_EXIST, "账号已在别处登录!");
            }
        }
        User user = userMapper.selectUserCodeBypwd(userCode);
        if (Objects.isNull(user)){
            return new ResponseResult(StatusCode.USER_PASSWORD_NULL, "该用户不存在!");
        }

        if(!user.getPassword().equals(password)){
            return new ResponseResult(StatusCode.PARAM_ERROR, "密码错误");
        }

        String token = CreateJwt.getoken(String.valueOf(user.getUid()), user.getUserCode());
        String macAddress = macAddressUtil.getMacAddress();
        System.out.println("本机Mac地址为" + macAddress);
        redisTemplate.opsForValue().set(MACAddress + userCode, macAddress);
        redisTemplate.opsForValue().set(USER_KEY + userCode,
                JSONUtil.parse("{\"token\":" + token + ", \"user\":"
                        + JSONUtil.parse(user) + "}"));

        Duration duration= Duration.ofMillis(USER_TIME);
        redisTemplate.expire(USER_KEY + userCode, duration);
        return new ResponseResult(StatusCode.SERVER_RUN_SUCCESS,
                JSONUtil.parse("{\"token\":" + token + ", \"user\":"
                        + JSONUtil.parse(user) + "}"),
                "用户" + user.getNickname() + "登录成功!")
                ;
    }
}

其中需要的工具类也给各位奉上

获取本机Mac地址:

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;

public class MacAddressUtil {
    public  String getMacAddress() {
        try {
            InetAddress localHost = InetAddress.getLocalHost();
            NetworkInterface networkInterface = NetworkInterface.getByInetAddress(localHost);
            byte[] macAddressBytes = networkInterface.getHardwareAddress();

            StringBuilder macAddressBuilder = new StringBuilder();
            for (int i = 0; i < macAddressBytes.length; i++) {
                macAddressBuilder.append(String.format("%02X%s", macAddressBytes[i], (i < macAddressBytes.length - 1) ? "-" : ""));
            }

            return macAddressBuilder.toString();
        } catch (UnknownHostException | SocketException e) {
            e.printStackTrace();
        }

        return null;
    }
}

JWT令牌

import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;

public class CreateJwt {

    //有效期为
    public static final Long JWT_TTL = 60 * 60 *1000L;// 60 * 60 *1000  一个小时

    public static String getoken(String uid, String userCode) {
        //Jwts.builder()生成
        //Jwts.parser()验证
        JwtBuilder jwtBuilder = Jwts.builder()
                .setId(uid + "")
                .setSubject(userCode)    //用户名
                .setIssuedAt(new Date())//登录时间
                .signWith(SignatureAlgorithm.HS256, "Like You Do").setExpiration(new Date(new
                        Date().getTime() + 30000));
//                .signWith(SignatureAlgorithm.HS256, "Like You Do").setExpiration(new Date(JWT_TTL));
        //设置过期时间

        return jwtBuilder.compact();
    }
}

集体响应类

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class ResponseResult {
    /**
     *  状态码
     */
    private Integer statusCode;

    /**
     * 数据
     */
    private Object data;

    /**
     * 提示信息
     */
    private String message;

    public ResponseResult(Integer statusCode, String message) {
        this(statusCode, null, message);
    }
}

状态码类

public class StatusCode {
    /**
     * 成功
     */
    public static final int SERVER_RUN_SUCCESS = 200;

    /**
     * 数据不存在
     */
    public static final int DATA_NOT_EXISTS = 400;

    /**
     * 密码错误
     */
    public static final int PASSWORD_ERROR = 401;

    /**
     * 添加失败
     */
    public static final int ADD_FAIL = 402;

    /**
     * 删除失败
     */
    public static final int DELETE_FAIL = 403;

    /**
     * 更新失败
     */
    public static final int UPDATE_FAIL = 408;

    /**
     * 用户不存在
     */
    public static final int USER_NOT_EXIST = 405;

    /**
     * 数据已存在
     */
    public static final int DATA_EXIST = 406;

    /**
     * 参数错误
     */
    public static final Integer PARAM_ERROR = 407;

    /**
     * 用户名或密码为空
     */
    public static final Integer USER_PASSWORD_NULL = 404;

    /**
     * 用户名或密码为空
     */
    public static final Integer REQUEST = 505;
}

controller层相应代码

import cn.hutool.db.handler.StringHandler;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import springboot_olmusic.service.UserService;
import springboot_olmusic.utils.ResponseResult;

import javax.annotation.Resource;

@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private UserService userService;

    @PostMapping("/login")
    public ResponseResult login(@RequestParam String userCode, String password){
        return userService.login(userCode, password);
    }
}

4.测试

最后,本文仅供参考,若发现bug欢迎指正

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值