基于若依前后端分离框架的小程序的token验证
后端和管理端都用的若依框架。
但是前段的小程序需要微信授权登录。这时候就需要在若依框架上重新再起一套token验证。
首先创建两个类(只要放在你能够引用得到的位置就可以):
第一个:实体
package com.ruoyi.system.toeknUnits;
public class WxLoginUser
{
private static final long serialVersionUID = 1L;
/**
* 用户ID
*/
private Long userId;
/**
* 部门ID
*/
private Long deptId;
/**
* 用户唯一标识
*/
private String token;
/**
* 登录时间
*/
private Long loginTime;
/**
* 过期时间
*/
private Long expireTime;
/**
* 登录IP地址
*/
private String ipaddr;
/**
* 登录地点
*/
private String loginLocation;
/**
* 浏览器类型
*/
private String browser;
/**
* 操作系统
*/
private String os;
private String openId;
private String nickName;
// getset我不粘贴了, 也可以使用lombok的@Data
}
第二个service:
package com.ruoyi.system.toeknUnits;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.AddressUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import eu.bitwalker.useragentutils.UserAgent;
import io.jsonwebtoken.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* token验证处理
*
* @author ruoyi
*/
@Component
public class WxTokenService
{
// 令牌自定义标识
@Value("${token.header}")
private String header;
// 令牌秘钥
private String secret = "这个自己随便定义一段英文";
// 令牌有效期(默认30分钟)
@Value("${token.expireTime}")
private int expireTime;
protected static final long MILLIS_SECOND = 1000;
protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;
private static final String wx_prefix = "tf";
@Autowired
private RedisCache redisCache;
/**
* 获取用户身份信息
*
* @return 用户信息
*/
public WxLoginUser getWxUser(HttpServletRequest request)
{
// 获取请求携带的令牌
String token = getToken(request);
if (StringUtils.isNotEmpty(token))
{
try
{
// 解析对应的权限以及用户信息
String userKey = token;
WxLoginUser user = redisCache.getCacheObject(userKey);
return user;
}
catch (Exception e)
{
e.printStackTrace();
}
}
return null;
}
/**
* 设置用户身份信息
*/
public void setWxLoginUser(WxLoginUser wxUser)
{
if (StringUtils.isNotNull(wxUser) && StringUtils.isNotEmpty(wxUser.getToken()))
{
refreshToken(wxUser);
}
}
/**
* 删除用户身份信息
*/
public void delWxUser(String token)
{
if (StringUtils.isNotEmpty(token))
{
String userKey = getTokenKey(token);
redisCache.deleteObject(userKey);
}
}
/**
* 创建令牌
*
* @param wxUser 用户信息
* @return 令牌
*/
public String createToken(WxLoginUser wxUser)
{
String token = IdUtils.fastUUID();
wxUser.setToken(token);
setUserAgent(wxUser);
refreshToken(wxUser);
Map<String, Object> claims = new HashMap<>();
claims.put(wx_prefix, token);
return createToken(claims);
}
/**
* 验证令牌有效期,相差不足20分钟,自动刷新缓存
*
* @param wxUser
* @return 令牌
*/
public void verifyToken(WxLoginUser wxUser)
{
long expireTime = wxUser.getExpireTime();
long currentTime = System.currentTimeMillis();
if (expireTime - currentTime <= MILLIS_MINUTE_TEN)
{
refreshToken(wxUser);
}
}
/**
* 刷新令牌有效期
*
* @param wxUser 登录信息
*/
public void refreshToken(WxLoginUser wxUser)
{
wxUser.setLoginTime(System.currentTimeMillis());
wxUser.setExpireTime(wxUser.getLoginTime() + expireTime * MILLIS_MINUTE);
// 根据uuid将loginUser缓存
String userKey = getTokenKey(wxUser.getToken());
redisCache.setCacheObject(userKey, wxUser, expireTime, TimeUnit.MINUTES);
}
/**
* 设置用户代理信息
*
* @param wxUser 登录信息
*/
public void setUserAgent(WxLoginUser wxUser)
{
UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
String ip = IpUtils.getIpAddr();
wxUser.setIpaddr(ip);
wxUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
wxUser.setBrowser(userAgent.getBrowser().getName());
wxUser.setOs(userAgent.getOperatingSystem().getName());
}
/**
* 从数据声明生成令牌
*
* @param claims 数据声明
* @return 令牌
*/
private String createToken(Map<String, Object> claims)
{
String token = Jwts.builder()
.setClaims(claims)
.signWith(SignatureAlgorithm.HS512, secret).compact();
return token;
}
/**
* 从令牌中获取数据声明
*
* @param token 令牌
* @return 数据声明
*/
private Claims parseToken(String token)
{
JwtParser parser = Jwts.parser();
JwtParser jwtParser = parser.setSigningKey(secret);
Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
Claims body = claimsJws.getBody();
System.out.println(body);
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}
/**
* 从令牌中获取用户名
*
* @param token 令牌
* @return 用户名
*/
public String getUsernameFromToken(String token)
{
Claims claims = parseToken(token);
return claims.getSubject();
}
/**
* 获取请求token
*
* @param request
* @return token
*/
public String getToken(HttpServletRequest request)
{
String token = request.getHeader(header);
if (StringUtils.isNotEmpty(token) && token.startsWith(wx_prefix))
{
token = token.replace(Constants.TOKEN_PREFIX, "");
return token;
}else{
return null;
}
}
private String getTokenKey(String uuid)
{
return "tf: " + uuid;
}
}
下一步: 找到
com.ruoyi.framework.security.filter;
这个文件
package com.ruoyi.framework.security.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.system.toeknUnits.WxLoginUser;
import com.ruoyi.system.toeknUnits.WxTokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.service.TokenService;
/**
* token过滤器 验证token有效性
*
* @author ruoyi
*/
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
{
@Autowired
private TokenService tokenService;
@Autowired
private WxTokenService wxTokenService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException
{
if( wxTokenService.getToken(request) == null){
System.out.println("管理员用户");
LoginUser loginUser = tokenService.getLoginUser(request);
if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication()))
{
tokenService.verifyToken(loginUser);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}else{
// 小程序逻辑
System.out.println("微信用户");
WxLoginUser wxUser = wxTokenService.getWxUser(request);
if (StringUtils.isNotNull(wxUser) && StringUtils.isNull(SecurityUtils.getAuthentication()))
{
wxTokenService.verifyToken(wxUser);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(wxUser, null, null);
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
chain.doFilter(request, response);
}
}
添加你获取code之类的。就是添加白名单。