token的作用和实现原理代码及验证token
程序员文章站
2022-07-02 23:30:05
...
token
在计算机身份认证中是令牌(临时)的意思,在词法分析中是标记的意思。一般作为邀请、登录系统使用。
http 请求的无状态性
JWT (jsonwebtoken)
用户登录 服务器端产生一个token (加密字符串) 发送给前端
前端将token 进行保存
前端发起数据请求的时候携带token
服务端 验证token 是否合法 如果合法继续操作 不合法终止操作
token 的使用场景 无状态请求 保持用户的登录状态 第三方登录
之所以遇到token是因为涉及到了微信第三方登录并绑定自己app端账户的手机号。
app端微信授权会给后端返回小程序登录时获取的 code
后端拿到code 并用 appid + secret+code+authorization_code(授权类型)
去请求微信的接口"https://api.weixin.qq.com/sns/jscode2session"
并得到返回来的唯一的标识 openId
可将openId 跟用户的唯一标识手机号进行绑定即可
而token 是在用户每次登录时候产生的 ,用于身份验证。
具体实现代码:
public class LoginController extends BaseController {
@Value("${weixin.shop.appid}")
private String appid;
@Value("${weixin.shop.secret}")
private String secret;
@Value("${token.name}")
private String serviceToken;
@Autowired
private IUserService userService;
@Resource
private CacheManager cacheManager;
// 小程序登录时获取的 code
String jsCode = req.getCode();
// 授权类型 authorization_code
String grantType = "authorization_code";
String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" + secret + "&js_code=" + jsCode + "&grant_type=" + grantType;
CloseableHttpClient client = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse res = client.execute(httpGet);
if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
HttpEntity entity = res.getEntity();
String result = EntityUtils.toString(entity, "UTF-8");
JSONObject jsonObject = JSON.parseObject(result);
Map<String, Object> map = new HashMap<String, Object>();
String openId = jsonObject.getString("openid");
if(openId != null && !"".equals(openId.trim())){
QueryWrapper<SysUser> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.eq("open_id", openId);
SysUser user = userService.getOne(userQueryWrapper);
if(user != null){
Cache cache = cacheManager.getCache("serviceCacheToken");
String uuid = UUID.randomUUID().toString().replaceAll("-","");
cache.put(uuid, user);
Map<String, String> resultMap = new HashMap<>();
resultMap.put(serviceToken, uuid);
return AjaxResult.success(resultMap);
}
return AjaxResult.success(1001, openId);
}
}
MSG = "未获得微信授权";
return AjaxResult.error(MSG);
}
}
而token是可以有时间限制的,比如两个小时之后便会失效。
可以在缓存的配置文件中配置token的生命周期
<defaultCache
name = "serviceCacheToken"
eternal = "false"
maxElementsInMemory = "10000"
overflowToDisk = "true"
diskPersistent = "false"
timeToIdleSeconds = "7200" // 这里就是token的有效时间 /秒
timeToLiveSeconds = "7200" // token的有效时间
diskExpiryThreadIntervalSeconds = "120"
memoryStoreEvictionPolicy = "LRU"/>
前端发起数据请求的时候可以在header中携带token去访问后端的接口
例如
String token = request.getHeader(serviceToken);
Cache cache = cacheManager.getCache("serviceCacheToken");
SysUser user = cache.get(token, SysUser.class);
后端可以验证token 然后进行下一步的操作
验证token具体代码:
/**
* 验证token
* @param joinPoint
* @return
* @throws Throwable
* @author: james
*/
@Around("validateToken()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
Object result = null;
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
String token = request.getHeader(serviceToken);
if(StringUtils.isEmpty(token)) {
return error(ErrorEnum.TOKEN_EMPTY.code, ErrorEnum.TOKEN_EMPTY.message);
}
try{
SysUser user = cacheManager.getCache("serviceCacheToken").get(token, SysUser.class);
if (user == null) {
return error(ErrorEnum.TOKEN_ERROR.code, ErrorEnum.TOKEN_ERROR.message);
}
}catch (Exception e){
return error(ErrorEnum.SYSTEM_ERROR.code, ErrorEnum.SYSTEM_ERROR.message);
}
result = joinPoint.proceed();
return result;
}
加油,一起进步!!!