【第5章】SpringBoot实战篇之登录模式切换


前言

前面分别介绍了本地Map和redis存储用户登录信息,但是第二天我登录就出现问题了,因为我Redis部署在虚拟机里面,不可能每次都专门启动虚拟机,来回替换代码也太麻烦,这里我们根据配置参数来控制下将用户信息存储到哪里。


一、接口扩展

开放扩展,关闭修改。

1. LoginStorage

package org.example.springboot3.bigevent.login;

/**
 * Create by zjg on 2024/6/3
 */
public interface LoginStorage {
    public void put(String id, String token);
    public String get(String id);
    public boolean remove(String id);
}

2. LocalLoginStorage

package org.example.springboot3.bigevent.login;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Create by zjg on 2024/6/3
 */
@ConditionalOnProperty(name="login.storage",havingValue = "0")
@Component
public class LocalLoginStorage implements LoginStorage{
    private Map<String,String> loginUsers=new ConcurrentHashMap<>(256);
    @Override
    public void put(String id, String token) {
        loginUsers.put(id, token);
    }

    @Override
    public String get(String id) {
        return loginUsers.get(id);
    }

    @Override
    public boolean remove(String id) {
        return loginUsers.remove(id)!=null;
    }

}

3. RedisLoginStorage

package org.example.springboot3.bigevent.login;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;

/**
 * Create by zjg on 2024/6/3
 */
@ConditionalOnProperty(name="login.storage",havingValue = "1")
@Component
public class RedisLoginStorage implements LoginStorage{
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Override
    public void put(String id, String token) {
        stringRedisTemplate.opsForValue().set(id,token,24, TimeUnit.HOURS);
    }

    @Override
    public String get(String id) {
        return stringRedisTemplate.opsForValue().get(id);
    }

    @Override
    public boolean remove(String id) {
        return Boolean.TRUE.equals(stringRedisTemplate.delete(id));
    }
}

4. 参数配置

这个参数控制使用本地存储、还是redis存储,这样扩展起来也方便。

login:
  storage: 0

二、登录相关接口改动

1.登录接口

@Autowired
LoginStorage loginStorage;
@RequestMapping("login")
public Result login(@Valid User loginUser){
   String message="用户名/密码不正确";
   User user = userSerivce.findUserByName(loginUser.getUsername());
   if(user!=null){//用户存在
       if(user.getPassword().equals(Md5Util.getMD5String(loginUser.getPassword()))){//密码正确
           Map<String,Object> claims=new HashMap();
           claims.put("userId",user.getId());
           claims.put("username",user.getUsername());
           String token = JwtUtils.create(claims);
           loginStorage.put(user.getId().toString(),token);
           return Result.success("登录成功",token);
       }
   }
   return Result.error(message);
}

2. 登录拦截器

@Autowired
LoginStorage loginStorage;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
   String token = request.getHeader("Authorization");
   if(token!=null&&token.contains("Bearer")){
       String tokenStr = token.substring(token.indexOf("Bearer") + 7);
       boolean verify = JwtUtils.verify(tokenStr);
       if(verify){//此处解析loginUsers,验证用户已登录
           Map<String, Object> claims = JwtUtils.getClaims(tokenStr);
           if(tokenStr.equals(loginStorage.get(claims.get("userId").toString()))){
               ThreadLocalUtil.set(claims);//用户信息放置ThreadLocal
               return true;
           };
       }
   }
   response.setStatus(HttpStatus.UNAUTHORIZED.value());
   response.setContentType("application/json;charset=UTF-8");
   ObjectMapper objectMapper = new ObjectMapper();
   objectMapper.writerFor(Result.class);
   String message = objectMapper.writeValueAsString(Result.error("token验证失败,请重新获取token后重试!"));
   response.getWriter().println(message);
   return false;
}


总结

回到顶部

这样我们就可以通过参数login.storage的修改,灵活地调整用户登录信息的存储方式了。
后面的登出接口和修改密码接口也会涉及到模式的使用。

相关推荐

  1. 5SpringBoot实战登录模式切换

    2024-06-06 00:32:04       8 阅读
  2. 《C++新经典设计模式5 观察者模式

    2024-06-06 00:32:04       29 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-06 00:32:04       14 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-06 00:32:04       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-06 00:32:04       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-06 00:32:04       18 阅读

热门阅读

  1. 游戏心理学Day02

    2024-06-06 00:32:04       7 阅读
  2. 枚举,typedef,位运算

    2024-06-06 00:32:04       7 阅读
  3. 如何在JVM中基于引用计数法实现GC

    2024-06-06 00:32:04       7 阅读
  4. 代码随想录leetcode200题之动态规划算法

    2024-06-06 00:32:04       7 阅读
  5. 裸机程序设计模式

    2024-06-06 00:32:04       8 阅读
  6. Leetcode-438-找到字符串中所有的字母异位词

    2024-06-06 00:32:04       6 阅读
  7. springboot请求中创建对象的被回收的过程

    2024-06-06 00:32:04       7 阅读
  8. 正缘画像 api数据接口

    2024-06-06 00:32:04       7 阅读
  9. 最大连续1 的个数Ⅲ(滑动窗口)

    2024-06-06 00:32:04       6 阅读
  10. 时间步和CLK之间的区别和联系

    2024-06-06 00:32:04       8 阅读
  11. Redis的非关系型数据库

    2024-06-06 00:32:04       7 阅读
  12. 深度学习之学习率调度器Scheduler介绍

    2024-06-06 00:32:04       11 阅读
  13. chap6 RNN

    2024-06-06 00:32:04       7 阅读
  14. FPGA编程与PLC编程的区别:深入解析与对比

    2024-06-06 00:32:04       9 阅读
  15. 解析自动驾驶算法四大模块的问题与后续发展

    2024-06-06 00:32:04       6 阅读
  16. iOS与前端:深入解析两者之间的区别与联系

    2024-06-06 00:32:04       9 阅读