令牌登录方式流程(token)

用户登录

登录需求分析
1:获取账号跟密码
2:通过账号密码查询数据库获取用户对象user
3:如果用户存在,表示登录成功
4:使用UUID创建出随机的唯一的token值
  String  token = ....
5:以token'为key,user为value 缓存到redis中
6:将token跟用户对象使用json格式放回浏览器

  浏览器:
		接受到返回值,解析出token跟用户信息,并缓存
		前端发起请求是,获取浏览器缓存的token值,通过请求头的方式携带到后端服务器
	接口2:
		1>通过请求对象获取前端传过来token
		String token =req.getHeader("token")
        2>以token为key,查Redis缓存库得到用户对象user
        3>判断user是否为null
----------------------------------------------------------------------
Session方式:
4:将user对象缓存到session中
	服务器:
	1>系统马上创建cookie对象
    Cookie c =new Cookie("jsessionid",xxx)
    2>使用response对象将cookie回传倒浏览器
    	response.addCookie(c)
    浏览器:
	1>浏览器接受cookie之后会缓存cookie
    2>第二次请求时,浏览器会自动将cookie携带到后端
    接口2:
		 1:通过请求对象获取session对象
    		1>请求对象获取cookie对象,然后解析出jsessionid
    		2>再通过jsessionid找到之前创建session对象
    	 2:通过session对象获取之前缓存的用户对象
令牌登录方式流程(token)
	1:通过请求获取username和password,查询数据库得到用户对象user
	2:通过user对象判断user是否为null,如果为null提示,如果不为null表示登录成功
	3:通过uuid方式创建token令牌(要求:随机,唯一)
        String token=UUID().randomUUID()...
    4:以token作为key,用户对象user作为value缓存到redis数据库中,token的有效时间设置为30分钟
    5:将token跟user对象使用json格式返回浏览器
    6:浏览器接受并解析响应数据得到token更user对象,缓存到cookie(此处的cookie也设置有效时间是30分钟)
---------------------------------------------------------------------------------------   
    7:第二次访问接口时,前端发送请求时,将浏览器缓存token数据添加到请求头中,跟请求参数一起携带到服务器
    8:服务器通过请求对象,调用String token =req.getHeader("token"),得到前端传过来的token数据
    9:以token为key查询redis缓存库,得到user对象
    10:判断user对象是否为null,决定当前是否已经登录
    	1>如果user为null,表示没有登录
    	2>如果user不为null,表示已经登录,登录成功后,此时必须重置token有效时间,不重置的话,30分钟又要重新登录,用户的体验会非常差
UserController
@RestController
@RequestMapping("/users")
public class UserController {
    //首次登录
	@PostMapping("/login")
    public Object login(String username, String password) {
        //1.验证手机号和密码是否正确,正确就返回用户信息,这个用来返回给前端
        UserInfo userInfo = userInfoService.login(username, password);
        //2.生成token并缓存,通过token拼接key,userInfo为value
        String token = userInfoRedisService.setToken(userInfo);
        //将userInfo和token存入map中
        HashMap<String, Object> map = new HashMap<>();
        map.put("token", token);
        map.put("user", userInfo);
        return JsonResult.success(map);
    }
    
    //再次登录获取token和user
    @RequireLogin
    @GetMapping("/currentUser")
    public Object currentUser(HttpServletRequest request) {
        String token = request.getHeader("token");
        //通过token查询redis库
        UserInfo userInfo = userInfoRedisService.getUserByToken(token);
        return JsonResult.success(userInfo);
    }
}
UserInfoServiceImpl(验证用户名和密码)
  @Service
public class UserInfoServiceImpl implements IUserInfoService {   
	//1.验证用户名和密码是否正确
    public UserInfo login(String username, String password) {
        UserInfo userInfo = userInfoRepository.findByPhone(username);
        if (userInfo == null || !userInfo.getPassword().equals(password)) {
            throw new LogicException("用户名或密码错误");
        }
        userInfo.setPassword("");
        return userInfo;
    }
}
UserInfoRedisServiceImpl(使用redis存取用户信息)
@Service
public class UserInfoRedisServiceImpl implements IUserInfoRedisService {
        @Autowired
       private StringRedisTemplate template;

     //2.生成token并缓存,通过token拼接key,userInfo为value
    @Override
    public String setToken(UserInfo userInfo) {
        //创建token
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        //生成key
        String key = RedisKeys.USER_LOGIN_TOKEN.join(token);
        String value = JSON.toJSONString(userInfo);//将对象转换为对象
        //缓存到redis中,并设置有效时间
        template.opsForValue().set(key, value, USER_LOGIN_TOKEN.getTime(), TimeUnit.SECONDS);
        return token;
    }
    -------------------------------------------------------------------------------------
        //再次登录
       //通过token查询出user
    @Override
    public UserInfo getUserByToken(String token) {
        //先判断是否为空
        if (!StringUtils.hasLength(token)) {
            return null;
        }
        //通过token拼接key
        String key = RedisKeys.USER_LOGIN_TOKEN.join(token);
        if (template.hasKey(key)) {
            String userStr = template.opsForValue().get(key);
            //将Json字符串解析为对象
            UserInfo userInfo = JSON.parseObject(userStr, UserInfo.class);
            //设置有效时间
            template.expire(key, RedisKeys.USER_LOGIN_TOKEN.getTime(), TimeUnit.SECONDS);
            return userInfo;
        }
        return null;
    }
}
redis中key键设计善于枚举类
//redis key重设计,因为在业务层设计key键会导致有可能和其他人设计名字重复,
//所有我们可以将key键统一放在枚举类中管理,这样key就不会重复了
@Getter
public enum RedisKeys {
    VERIFY_CODE("verify_code", Consts.VERIFY_CODE_VAI_TIME * 60L),
    USER_LOGIN_TOKEN("user_login_token", Consts.USER_INFO_TOKEN_VAI_TIME * 60L);
    //相当于下面写法
    //public static final RedisKeys VERIFY_CODE
    // =new RedisKeys("verify_code", Consts.VERIFY_CODE_VAI_TIME * 60L);
    private String prefix;
    private Long time;

    private RedisKeys(String prefix, Long time) {
        this.prefix = prefix;
        this.time = time;
    }

    //用于拼接key
    public String join(String... values) {
        StringBuilder sb = new StringBuilder();
        sb.append(prefix);
        for (String value : values) {
            sb.append(":").append(value);
        }
        return sb.toString();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值