后端登录安全的一种思路

PS:作者是小白能接触到的就只会这样写。勿喷。

前提

思路: 结合io流将登录token存储到配置文件中,不将token存储到浏览器端,从而避免盗取。

下面jwt的学习可以参考下这个:

JWT --- 入门学习_本郡主是喵的博客-CSDN博客

JWT工具类

@Component
public class JWTtUtils {

    public static final String USER_NAME = "username";
    public static final String PASS_WORD = "password";
    public static final String CREATE_TIME = "createTime";
    public static final String SIGN_KEY = "QHX2004"; // 解析key
    /**
     * 用用户名和密码生成JWT
     *
     * @param username
     * @param password
     * @return
     */

    public String generatorJWTFromUserNameAndPassword(String username,String password){
        HashMap<String, Object> hashMap = new HashMap<>(); // 生成map
        hashMap.put(USER_NAME,username);
        hashMap.put(PASS_WORD,password);
        hashMap.put(CREATE_TIME,new Date());
        return  generatorJWTFromUserNameAndPassword(hashMap);
    }

    /**
     * 生成jwt过期时间,1个月
     *
     * @param
     * @return
     */
    private Date generatorExpirationDate() {
        return new Date(System.currentTimeMillis() + (1000L * 60 * 60 *24 *30));
    }

    /**
     * 用用户名和密码生成jwt
     *
     * @param paramMap
     * @return
     */
    private String generatorJWTFromUserNameAndPassword(HashMap<String, Object> paramMap) {
        JwtBuilder jwtBuilder = Jwts.builder()
                .setClaims(paramMap)
                .setExpiration(generatorExpirationDate()) // 设置过期时间
                .signWith(SignatureAlgorithm.HS512,SIGN_KEY);
        return jwtBuilder.compact(); // 拿到token
    }



    /**
     * 解析token拿到Claims
     *
     *
     * @param token
     * @return
     */
     private Claims getClaimsFromToken(String token){
        Claims claims = Jwts.parser()
                .setSigningKey(SIGN_KEY)
                .parseClaimsJws(token)
                .getBody();

        return claims;
    }

    /**
     * 校验token是否过期
     *
     * @param token
     * @return
     */
  // 过期返回true
    public boolean checkTokenIsOverdue(String token){
        Claims claims = getClaimsFromToken(token);
        Date date =  claims.getExpiration();
        return date.getTime() < new Date().getTime();
    }


    /**
     * 刷新token:重新生成一个token
     *
     * @param
     * @return
     */

    public String flushToken(String token){
        Claims claims = getClaimsFromToken(token);
        String username = (String) claims.get(USER_NAME);
        String password = (String)claims.get(PASS_WORD);
        return generatorJWTFromUserNameAndPassword(username,password);
    }

}

IO工具类

public class IOUtils {


    public static final String FILE_NAME = "conf.properties";

    /**
     *   配置文件读取
     * @param key
     * @return  value
     */

    public static String getPropertiesKey(String key)  {
      return  getKey(key);
    }

    /**
     * 配置文件读取
     *
     * @param  key
     * @return
     */
    private static String getKey(String key) {
        Properties properties = new Properties();
        File file = new File(FILE_NAME);
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
            properties.load(inputStream); // 其实已经将配置文件拿到手了
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(inputStream != null){  // 还是这样关比较好,万一报错就tm关不了
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return  properties.getProperty(key);
    }

    /**
     * 配置文件设置
     *
     * @param key
     * @param value
     * @return
     */
    public static boolean setPropertiesKey(String key,String value) {
        // 判断key是否有重复
        String key1 = getKey(key);
        if(key1 == null){
            return setKey(key,value); // 把核心业务逻辑抽出来
        }
        return false;
    }

    /**
     *  配置文件设置
     *
     * @param key
     * @param value
     * @return boolean
     */
    private static boolean setKey(String key, String value) {
        Properties properties = new Properties();
        File file = new File(FILE_NAME); // 其实有其他配置可以同意下yaml文件里面配置,然后这里面读取,好统一调配。
        FileWriter fileWriter = null;
        try {
            fileWriter = new FileWriter(file,true);
            properties.setProperty(key, value); // 存进map里面
            properties.store(fileWriter,""); // 将map对应的键值对写进输出流。
        } catch (IOException e) {
            // 卧槽我加入设置key,value失败,肯定调到这个逻辑
            return false;
        } finally {
            if (fileWriter != null) {  // 还是这样关比较好,万一报错就tm关不了
                try {
                    fileWriter.flush();
                    fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

}

测试文件

@SpringBootTest
class IoDemoApplicationTests {

    @Test
    void contextLoads() {
        // 用户第一登录 ----,我们这里浏览器端不存token,只存用户名,更安全。
        String username = "qhx2005";
        String password = "123456";
        // 生成jwt
        JWTtUtils jwTtUtils = new JWTtUtils();
        String token = jwTtUtils.generatorJWTFromUserNameAndPassword(username, password);
        // 将jwt存进配置文件
        boolean success = IOUtils.setPropertiesKey(username, token);
        System.out.println("存进配置文件成功状态:"+success);
        assert success;


        // 用户登录后访问其他页面。检验token过期,拿出配置文件是否存在----
        // 获取token
        String token1 = IOUtils.getPropertiesKey(username);
        System.out.println(token1);
        // 检验token是否过期
        boolean overdue = jwTtUtils.checkTokenIsOverdue(token);
        // 本来这里如果token过期,我们响应一个状态码,让前端axios过滤器捕获到,删除本地username,重定向到登录页。
        System.out.println("已经过期:"+overdue);

    }

}

猜你喜欢

转载自blog.csdn.net/Qhx20040819/article/details/132101311