最近一直在做前后端分离项目,开始想研究如何从实现remember me问题,可以使用JWT token。我的想法是把用户的id或者用户名(最好不要加上password)保存在token令牌中,每次提交时携带上token令牌后台验证是否失效,没有失效的话可以继续后面的操作。失效的话返回登录界面重新登录。
JWT token的组成
头部(Header),格式如下:
{
“typ”: “JWT”,
“alg”: “HS256”
}
由上可知,该token使用HS256加密算法,将头部使用Base64编码可得到如下个格式的字符串:
eyJhbGciOiJIUzI1NiJ9
- 1
有效载荷(Playload):
{
“iss”: “Online JWT Builder”,
“iat”: 1416797419,
“exp”: 1448333419,
…….
“userid”:10001
}
有效载荷中存放了token的签发者(iss)、签发时间(iat)、过期时间(exp)等以及一些我们需要写进token中的信息。有效载荷也使用Base64编码得到如下格式的字符串:
eyJ1c2VyaWQiOjB9
- 1
签名(Signature):
将Header和Playload拼接生成一个字符串str=“eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOjB9”,使用HS256算法和我们提供的密钥(secret,服务器自己提供的一个字符串)对str进行加密生成最终的JWT,即我们需要的令牌(token),形如:str.”签名字符串”。
下面代码是网上粘下来的,因为自己的代码不在这台电脑上>.<.
private static Logger log = LoggerFactory.getLogger(JavaWebToken.class); //该方法使用HS256算法和Secret:bankgl生成signKey private static Key getKeyInstance() { //We will sign our JavaWebToken with our ApiKey secret SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary("bankgl"); Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName()); return signingKey; } //使用HS256签名算法和生成的signingKey最终的Token,claims中是有效载荷 public static String createJavaWebToken(Map<String, Object> claims) { return Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS256, getKeyInstance()).compact(); } //解析Token,同时也能验证Token,当验证失败返回null public static Map<String, Object> parserJavaWebToken(String jwt) { try { Map<String, Object> jwtClaims = Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(jwt).getBody(); return jwtClaims; } catch (Exception e) { log.error("json web token verify failed"); return null; }
后来我想到了安全问题,如果某个人拿到了我的token不就可以登陆我的账号了吗。
我的几种解决方案:
1.可以将ip保存在token令牌中,验证ip是否一致,不一致就重新输入。
2.把token的时效设置的短一点,经常更换(这招可以用来防止爬虫)。
每次都需要获取token,所以最好在filter中判断一下,就不必在每个controller中在获取判断了。
这种思想也可以用来作防止表单重复提交。