2020年02月28日 10:14(zuul网关转发请求遇到的问题)
当我在测试配置网关转发时,发现另一模块根据令牌来云平台取数据的时候,通过实际地址令牌有效,通过网关转发获取不到数据。
排查后发现我使用了shiro的session来为请求提供数据,而session是跟客户端绑定的,网关转发相当于另一个客户端,sessionId是不一致的所以取不到我们之前存的数据,所以在使用网关转发请求的时候,获取的数据不要放在session中,放在缓存或数据源中并且要开放拦截,道理跟上边一样,你实际客户端的认证对于网关转发请求是不认的,他认为你是另一客户端。
2020年03月03日 09:53(mybatis的参数传递问题)
org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'isAdmin' in 'class java.lang.String'
当我传递了isAdmin参数进行查询时报出了错误,在之前使用spring类型参数不适应param标签是没有问题的,这次我使用了where和if的标签,所以必须使用param给定义参数才可以在xml的标签里使用
2020年03月05日 10:45(客户端与服务端的session问题+redis时间设置问题)
之前说了客户端与服务端的token数据是存在session中的,尽管我放开了拦截,但是我们的token是要经过转发到子系统使用的,子系统的开发人员跟我沟通发现在他登陆后进入子系统根据获取到的token通过postman也好get请求也好都可以获取到用户信息,但是他把token交给后台通过内部请求调用获取到的用户信息为空,然后我发现在你登陆后再退出哪怕服务端还有session信息,但是客户端的信息发生改变,之前说过session的绑定是通过客户端的sessionId的,所以客户端信息发生改变服务端找不到信息返回了null,之前也是临时测试放到session中,这次正好放到redis里。
在我放到redis的方法中我使用的下面的代码
@Autowired
private RedisTemplate redisTemplate;
ValueOperations<String, User> operations = redisTemplate.opsForValue();
// 插入缓存
operations.set("token:"+token, user, 10, TimeUnit.SECONDS);
但是很快就出现了问题,我在存储redis的时候没有问题,但是在用户根据token取信息的时候一直是null,我断点检查问题,发现传递token跟redis的key不符合,下面是我生成token的代码,示例为Nv6RRuGEVvmGjB+jimI/gw==,但是浏览器传递过来的信息将/ + == 这些特殊符号给屏蔽了,于是不对应的key当然取不到信
/**
* 生成Token
* Token:Nv6RRuGEVvmGjB+jimI/gw==
* @return
*/
public String makeToken(){
String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";
//数据指纹 128位长 16个字节 md5
try {
MessageDigest md = MessageDigest.getInstance("md5");
byte md5[] = md.digest(token.getBytes());
//base64编码--任意二进制编码明文字符 adfsdfsdfsf
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(md5);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
我暂时将token换成了uuid发现还是取不到用户信息,但是将存和取放到同一方法一起执行没有问题,经过很长时间的排查,我发现了上面设置缓存时间的TimeUnit这个东西,TimeUnit在上面redis插入的使用是定义时间单位的
operations.set("token:"+token, user, 10, TimeUnit.SECONDS);// key value 超时时间 时间单位
TimeUnit.DAYS //天
TimeUnit.HOURS //小时
TimeUnit.MINUTES //分钟
TimeUnit.SECONDS //秒
TimeUnit.MILLISECONDS //毫秒
TimeUnit.SECONDS是秒,我设置了10秒的超时,怪不得每次用户拿不到value
修改一下设置
ValueOperations<String, User> operations = redisTemplate.opsForValue();
// 插入缓存
operations.set("token:"+token, user, 30, TimeUnit.MINUTES);
30分钟的超时时间,这样就好了,当然token并不是无限生成的,这时候我用上了session,在用户的这一次登陆中他第一次去子系统时会获取token并且存到session里,第二次如果session里有token直接跳过返回session的token,这样就不会频繁创建token从而降低redis的压力,当然用户注销重登再访问是会重新创建的,跟上面将的一样,客户端发生改变,之前的session对于客户端相当于失效了。