在前后端分离开发的现在,token是一个必须的技术,虽然不难,但是这篇文章对于小白自己学的话,还是有点用的,以后也可来这进行代码的拷贝啊,四把!
token是对session的一个升级,解决了前后端分离的session不能共享的一个难题,token一般保存与redis中,对于redis的代码书写我也写有文章,可以进行查看,将token存放在redis中,前端每一次请求都会在请求头中存放token,我们只需要进行拿去token就可以进行对比,判断token是否存在,从而验证用户的合法性
话不多说了,来货咯!
这里是tokenservice的接口,定义了一下token的操作
package com.kgc.service.userservice;
import com.kgc.pojo.DmUser;
/*token管理业务接口*/
public interface TokenService {
/*
* 会话超时时间,默认2小时
*/
public final static int SESSION_TIMEOUT=2*60*60;
/*
*置换保护时间,默认1小时
*/
public final static int REPLACEMENT_PROTECTION_TIMEOUT=60*60;
/*
*旧token延迟过期时间
*/
public final static int REPLACEMENT_DELAY=2*60;
/*
* 生成token
* @param agent Http头中的user-agent信息
* @param user 用户信息
* @return Token格式<br/>
* PC: "前缀PC-USERCODE-USERID-CREATIONDATE-RONDEM[6位]"
* <br/>
* Android:"前缀ANDOIRD-USERCODE-CREATIONDATE-RONDEM[6位]"
*/
public String generateToken(String agent, DmUser user) throws Exception;
/*
* 保存用于信息至redis
* @param token token字符串
* @param user 用户信息
*/
void save(String token, DmUser user) throws Exception;
/*
* 从redis中获取用户信息
* @param token token字符串
* @return 对象
*/
public DmUser load(String token) throws Exception;
/*
* 置换token<br/>
* 1. 首先要判断token是否有效<br/>
* 2. 生成token后的1个小时内部允许置换<br/>
* 3. 置换token时, 需要生成新token, 并且旧token不能立即失效,
* 应设置置换后的时间延长2分钟<br/>
* 4. 兼容手机端和PC端<br/>
* @param agent http头信息的user-agent
* @param token token 字符串
* @return
*/
public String replaceToken(String agent, String token) throws Exception;
/*
* 验证token是否有效
* @param agent http头信息的user-agent
* @param token token 字符串
* @return
*/
public boolean validate(String agent, String token) throws Exception;
}
这里是tokenserviceimplement实现的代码,是具体的token的实现
package com.kgc.service.userservice;
import com.alibaba.fastjson.JSON;
import com.kgc.pojo.DmUser;
import com.kgc.utils.MD5;
import com.kgc.utils.RedisUtils;
import com.kgc.utils.UserAgentUtil;
import cz.mallat.uasparser.UserAgentInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/*
* token管理业务接口实现类
*/
@Service
public class TokenServiceImpl implements TokenService {
@Autowired
private RedisUtils redisAPI;/*建立缓存服务器对象*/
@Override
/*
* ticket的生成
* */
public String generateToken(String agent, DmUser user) throws Exception {
StringBuffer sb=new StringBuffer("token:");
/*获取到请求客户端信息*/
UserAgentInfo userAgentInfo= null;
try {
userAgentInfo = UserAgentUtil.getUasParser().parse(agent);
//判断发送请求的是否是移动端
if(userAgentInfo.getDeviceType().equals(UserAgentInfo.UNKNOWN)) {/*未知的*/
if (UserAgentUtil.CheckAgent(agent)) {
sb.append("MOBILE-");/*是移动端的*/
} else {/*不是移动端*/
sb.append("PC-");
}
}else if(userAgentInfo.getDeviceType().equals("Personal computer")){
sb.append("PC-");
}else{
sb.append("MOBILE-");
}
if(user.getPhone()!=null){
sb.append(MD5.getMd5(user.getPhone(),32)+"-");/*将用户的账号进行加密*/
}else{
sb.append(user.getSex()+"-");/*将用户的账号进行加密*/
}
sb.append(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())+"-");/*生成唯一的ticket*/
sb.append(MD5.getMd5(agent,6));//对agent进行加密
return sb.toString();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/*
* 保存ticket
* */
@Override
public void save(String token, DmUser user) throws Exception {
if(!redisAPI.exist(token)){/*判断token是否存在*/
System.out.println(token.startsWith("token: PC-")+"HJKL;");
if(token.startsWith("token:PC-")){/*判断是否是PC端的*/
redisAPI.set(token ,TokenService.SESSION_TIMEOUT, JSON.toJSONString(user));
}else{
redisAPI.set(token,JSON.toJSONString(user));
}
}
}
/*
*
* 加载token
* */
@Override
public DmUser load(String token) {
String Dmuser = (String) redisAPI.get(token);
return JSON.parseObject(Dmuser,DmUser.class);
}
/*
* 替换token
*
* */
@Override
public String replaceToken(String agent, String token) throws Exception {
/*验证token是否存在*/
if(!redisAPI.exist(token)){
throw new Exception("token未知或已过期!");
}
/*token存在
*
* 将token进行拆分
* */
String []tokenDetials=token.split("-");//拆分token为tokenDetials数组
SimpleDateFormat format=new SimpleDateFormat("yyyyMMddHHmmss");//获取当前时间
Date tokenGenTime=format.parse(tokenDetials[2]);//获取token中的token生成的时间
/*获取token生成了的时间*/
long passed=Calendar.getInstance().getTimeInMillis()-tokenGenTime.getTime();
/*判断是否token在保护时间内*/
if(passed< TokenService.REPLACEMENT_PROTECTION_TIMEOUT*1000){
return ("token还在保护期间,不允许替换");
}
//替换token
String newToken="";
/*获取到token对应的user对象*/
DmUser icyUser=this.load(token);
//创建新的token
newToken=this.generateToken(agent,icyUser);
this.save(newToken,icyUser);
redisAPI.set(token, TokenService.REPLACEMENT_DELAY,JSON.toJSONString(icyUser));
return newToken;
}
/*
* 验证token
* */
@Override
public boolean validate(String agent, String token)throws Exception {
if(!redisAPI.exist(token)){
return false;
}
SimpleDateFormat format=new SimpleDateFormat("yyyyMMddHHmmss");
String [] tokenDetails=token.split("-");//拆分token
Date date= null;//获取token中的时间
try {
/*date为null,抛出异常*/
date = format.parse(tokenDetails[2]);
/*获取token生成时长*/
long passed=Calendar.getInstance().getTimeInMillis()-date.getTime();
if(passed> TokenService.SESSION_TIMEOUT*1000){
return false;/*token失效*/
}
String agentMD5=tokenDetails[3];//获取请求头中的token数据
System.out.println(agentMD5);
String newAgentM5=MD5.getMd5(agent,6);//对token进行加密
System.out.println(newAgentM5);
if(newAgentM5.equals(agentMD5)){
return true;
}
} catch (ParseException e) {
e.printStackTrace();
}
return false;
}
}
对于有基础的人来说,token实现类中的调用我就不要说啦吧,就是简单的面向对象啊,调用就可以了!
别的就没有咯,要是有兴趣的关注我,博客还有好多哦,我会慢慢写的,当然是我自己学的东西,不具有太高的准确性。哈哈
转载记得加链接!