文章目录
前言
前面分别介绍了本地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;
}
总结
标签:实战篇,SpringBoot,登录,public,token,org,import,id,String From: https://blog.csdn.net/qq_44824164/article/details/139425658这样我们就可以通过参数
login.storage
的修改,灵活地调整用户登录信息的存储方式了。
后面的登出接口和修改密码接口也会涉及到模式的使用。