1. 用户注册功能开发和MD5加密工具类封装
用户注册提交手机号phone、姓名、头像等信息,通过判断手机号来判断是否是新用户
private User parseToUser(Map<String,String> userInfo) {
if(userInfo.containsKey("phone") && userInfo.containsKey("pwd") && userInfo.containsKey("name")){
User user = new User();
user.setName(userInfo.get("name"));
user.setHeadImg(getRandomImg());
user.setCreateTime(new Date());
user.setPhone(userInfo.get("phone"));
String pwd = userInfo.get("pwd");
//MD5加密
user.setPwd(CommonUtils.MD5(pwd));
return user;
}else {
return null;
}
}
如果想要更安全一点,可以对MD5后的值再进行一次MD5
具体原理参考如下MD5加密概述,原理及实现
2.单机和分布式应用的登录校验解决方案
2.0. Session原理
Session原理
当访问服务器一个网页的时候,会在服务器端的内存里开辟一块内存,这块内存就叫做session,而这个内存是跟浏览器关联在一起的(浏览器在session就在)。Session用来记录一系列状态。
Session与cookie功能效果相同。Session与Cookie的区别在于Session是记录在服务端的,而Cookie是记录在客户端的。
Cookie
Cookie包含用户个人信息,再次通过浏览器发送给服务器时,会放在http响应头(弥补HTTP协议无状态的不足,即一次连接完成后打开新的页面就无法追踪上一个页面信息,有了Cookie服务器会记住我)
2.1. 单机tomcat应用登录检验
- 用户登录成功,服务端会保存一个session,当然客户端客户端有一个sessionId
- 客户端会把sessionId保存在cookie中,每次请求都会携带这个sessionId
2.2. 分布式应用中session共享
- 真实的应用不可能单节点部署,所以就有个多节点登录session共享的问题需要解决
- tomcat支持session共享,但是有广播风暴;用户量大的时候,占用资源就严重,不推荐
- 使用redis存储token:
- 服务端使用UUID生成随机64位或者128位token,放入redis中,然后返回给客户端并存储在cookie中
- 用户每次访问都携带此token,服务端去redis中校验是否有此用户即可
3.分布式应用下登录检验解决方案 JWT
3.1. 从token开始
token : 客户端使用用户名和密码请求登录,服务端收到请求,验证用户名和密码成功后会签发一个token,再把这个token返回给客户端。客户端收到token后可以把它存储起来,比如放到cookie中客户端每次向服务端请求资源时需要携带服务端签发的token,可以在cookie或者header中携带。
3.2. JWT是啥
JWT:就是上述流程当中token的一种具体实现方式,其全称是JSON Web Token
,官网地址:https://jwt.io/ 通俗地说,JWT的本质就是一个字符串(以JSON加密形式保存在客户端),它是将用户信息保存到一个Json字符串中,然后进行编码后得到一个JWT token,并且这个JWT token带有签名信息,接收后可以校验是否被篡改,所以可以用于在各方之间安全地将信息作为Json对象传输。
3.3. 为什么用JWT
为什么用JWT:
1.生产的token可以包含基本信息,比如id、用户昵称、头像等信息,避免再次查库;
2.存储在客户端,不占用服务端的内存资源;
3.狂操session:JWTtoken单点登录友好,使用Session进行身份认证的话,由于cookie无法跨域,难以实现单点登录。但是 token可以被保存在客户端的任意位置的内存中,不一定是cookie,所以不依赖cookie。适合移动端应用:使用Session进行身份认证的话,需要保存一份信息在服务器端,而且这种方式会依赖到Cookie(需要 Cookie 保存 SessionId),所以不适合移动端。(本质都是session依赖保存在本地的cookie)
3.3. JWT使用步骤
使用步骤:
1.首先,前端通过Web表单将自己的用户名和密码发送到后端的接口,一般是一个POST请求(建议HTTPS)。
2.后端核对用户名和密码成功后,将包含用户信息的数据作为JWT的Payload,将其与JWT Header分别进行Base64编码拼接后签名,形成一个JWT Token,形成的JWT Token就是一个如同lll.zzz.xxx的字符串。
3.后端将JWT Token字符串作为登录成功的结果返回给前端。前端可以将返回的结果保存在浏览器中,退出登录时删除保存的JWT Token即可。
4.前端在每次请求时将JWT Token放入HTTP请求头中的Authorization属性中(解决XSS和XSRF问题)。
5.后端检查前端传过来的JWT Token,验证其有效性,比如检查签名是否正确、是否过期、token的接收方是否是自己等等。
6.验证通过后,后端解析出JWT Token中包含的用户信息,进行其他逻辑操作(一般是根据用户信息得到权限等),返回结果。
- 引入依赖
- 将user对象包装成token
/**
* 根据用户信息,生成令牌
* @param user
* @return
*/
public static String geneJsonWebToken(User user){
String token = Jwts.builder().setSubject(SUBJECT)
.claim("head_img",user.getHeadImg())
.claim("id",user.getId())
.claim("name",user.getName())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
.signWith(SignatureAlgorithm.HS256,SECRET).compact();
token = TOKEN_PREFIX + token;
return token;
}
- 检查token
/**
* 校验token的方法
* @param token
* @return
*/
public static Claims checkJWT(String token){
try{
final Claims claims = Jwts.parser().setSigningKey(SECRET)
.parseClaimsJws(token.replace(TOKEN_PREFIX,"")).getBody();
return claims;
}catch (Exception e){
return null;
}
}
3.4. JWT结构
JWT由3部分组成:标头(Header)、有效载荷(Payload)和签名(Signature)。在传输的时候,会将JWT的3部分分别进行Base64编码
后用.进行连接形成最终传输的字符串。
- 头部:主要是描述签名算法
- 负载:主要描述是加密对象的信息,如用户的id等,也可以加些规范里面的东西,如iss签发者,exp 过期时间,sub 面向的用户
- 签名:主要是把前面两部分进行加密,防止别人拿到token进行base解密后篡改token