一、生成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{
}