一、生成token

后端利用生成token的方式来进行用户状态的保持和验证,token简单的解释就是后端通过一些唯一的值(比如当前时间,用户ID等)拼接起来的字符串。
在登陆业务中,

  • 首先根据用户名和密码在数据库中查找,如果存在则继续下面的流程
  • 接下来是生成token
//编写一个 获取token的方法
private String getNewToken(String timeStr,Long userId){
	//参数是一个时间戳字符串和用户ID
	String src = timeStr + userId + NumberUtil.genRandomNum(4);
	return SystemUtil.genToken(src);
}

..
..
..
//其中NumberUtil.genRandomNum(4) 生成指定长度的随机数
public static int genRandomNum(int length){
	int num = 1;
	double random = Math.random();//随机生成一个0~1之间的数,不包含1
	if(random < 0.1){
		random = random + 0.1;
	}
	for(int i = 0; i < length; i++){
		num = num * 10;
	}
	return (int)((random * num));
}
..
..
//其中SystemUtil.genToken(src)为 登陆或者注册成功后,生成保持用户登陆状态会话token值
public static String genToken(String src){
	if(null == src || "",equals(src){
		return null;
	}
	try{
		//MessageDigest是Java自带的加密类,XX.getInstance("MD5")意为加密MD5
		MessageDigest md = MessageDigest.getInstance("MD5");
		//使用指定的byte来更新md
		md.update(src.getBytes());
		//md.digest() 生成摘要, 
		//new BigInteger(int sinnum,byte[] magnitude),构造方法,
		//-1表示负数,0表示0,1表示正数
		String result = new BigInteger(1,md.digest()).toString(16);
		if(result.length() == 31){
			result = result + "-";
		}
		System.out.println(result);
		return result;
	}catch(Exception e){
		return null;
	}
}
  • 然后根据用户ID查询token信息,如果无token信息,则新增一个;如果有则更新
  • 在新增或者更新里有个字段,要注意一个过期时间,过期时间是当前时间再加48小时
  • 封装用户Token信息并进行入库操作
  • 最后返回token值

二、获取到前端请求中的token值

完成登陆后,需要对用户的登陆状态进行验证,这里的登陆状态可以解释为“Token值是否存在以及Token 值是否有效” token是否有效通过后端代码实现,由于大部分接口都需要进行登陆验证,如果每个方法都添加查询用户数据的语句则有些多余,因此对方法做了抽取,通过注解切面的形式来返回用户信息

  • 自定义参数注解
    我们自定义@TokenUser注解,使用注解和AOP方式将用户对象注入到方法中:
package com.kenny.mall.config.annotation;

import java.lang.annotation.*;

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TokenUser{
	//当前用户在request中的名字
	String value() default "user";
}
  • 自定义方法参数解析器
    在需要用户身份信息的方法中加上@TokenUser注解,之后通过方法参数解析器来获取当前登陆的对象信息
    自定义方法参数解析器ToeknUserMethodArgumentResolver,需实现HandleMethodArgumentResolver类,代码如下
package com.kenny.mall.config.handler;
import com.kenny.mall.common.Constants;
import com.kenny.mall.MallException;
import com.kenny.mallcommon.ServiceResultEnum;
import com.kenny.mall.config.annotation.TokenUser;
import com.kenny.mall.dao.MallUserMapper;
import com.kenny.mall.dao.MallUserTokenMapper;
import com.kenny.entity.MallUser;
import com.kenny.entity.MallUserToken;
import org.springframwork.beans.factory.annotation.Autowired;
import org.springframword.core.MethodParameter;
import org.springframword.stereotype.Component;
import org.springframword.web.bind.support.WebDataBinderFactory;
import org.springframword.web.context.request.NativeWebRequest;
import org.springframword.web.method.support.HandlerMethodArgumentResolver;
import org.springframword.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@Component
public class TokenUserMethodArgumentResolver implements HandlerMethodArgumentResolver{

}

三、验证token值,是否存在、是否过期等等。

四、参数注解