一、用户身份认证
单一服务器:
对于单一服务器来说:(用户访问有以下5个步骤)
1.用户向服务器发送用户名和密码
2.验证服务器后,相关的数据(用户名和用户角色等)将保存在当前的 Session会话中。
3.Web服务器向用户发送Session_id,session信息就会存储在Cookie。
4.之后的用户每个请求都会从Cookie中取出这个Session_id传给服务器。
5.服务器收到Session_id 并对比之前保存的数据,确认用户的身份
存在的问题:
单点性能压力,无法拓展
分布式架构中,需要Session的共享方案,Session共享方案存在技术瓶颈
简单点理解:
有多个Web服务器的时候 每个服务器都会生成自己的Session_id,这样就出现了多次提醒登录的冲突。
解决方案有二种:
一、sos模式(CAS单点登入 OAuth2)
二、Token模式(项目中使用的是Token模式)
优点:
- Token是无状态的 Session是有状态的
- 基于标准化:你的API可以采用标准化的JSON Web Token(JWT)
缺点:
1.占用带宽
2.无法在服务器端销毁
访问令牌的类型有两种:
- 通明令牌
- 自包含令牌
JWT令牌
JWT是JSON Web令牌,是一种自包含令牌
JWT的作用:
- 就是对Token信息的防伪作用 (判断你发来的Token是真假)
JWT的原理
- 一个JWT是由三部分组成的:JWT的头、有效载荷、签名哈希
- 最后由三者的组合进行base64编码得到JWT
JWT的用法
- 客户端接受返回的JWT,将其存储在Cookie中
- 客户端向服务器端发送请求的时候就会带着JWT,一般存在Cookie中就会自动发送,但是不会跨域,因此一般将它放在http请求的请求头中
- 当跨域的时候,也可以将它放在POST请求的数据主体中
生成Token的依赖:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
工具类
public class JwtUtils {
private static long tokenExpiration = 24*60*60*1000;
private static String tokenSignKey = "A1t2g3uigu123456";
private static Key getKeyInstance(){
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
byte[] bytes = DatatypeConverter.parseBase64Binary(tokenSignKey);
return new SecretKeySpec(bytes,signatureAlgorithm.getJcaName());
}
public static String createToken(Long userId, String userName) {
String token = Jwts.builder()
.setSubject("SRB-USER")
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
.claim("userId", userId)
.claim("userName", userName)
.signWith(SignatureAlgorithm.HS512, getKeyInstance())
.compressWith(CompressionCodecs.GZIP)
.compact();
return token;
}
/**
* 判断token是否有效
* @param token
* @return
*/
public static boolean checkToken(String token) {
if(StringUtils.isEmpty(token)) {
return false;
}
try {
Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(token);
return true;
} catch (Exception e) {
return false;
}
}
public static Long getUserId(String token) {
Claims claims = getClaims(token);
Integer userId = (Integer)claims.get("userId");
return userId.longValue();
}
public static String getUserName(String token) {
Claims claims = getClaims(token);
return (String)claims.get("userName");
}
public static void removeToken(String token) {
//jwttoken无需删除,客户端扔掉即可。
}
/**
* 校验token并返回Claims
* @param token
* @return
*/
private static Claims getClaims(String token) {
if(StringUtils.isEmpty(token)) {
// LOGIN_AUTH_ERROR(-211, "未登录"),
throw new BusinessException(ResponseEnum.LOGIN_AUTH_ERROR);
}
try {
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
return claims;
} catch (Exception e) {
throw new BusinessException(ResponseEnum.LOGIN_AUTH_ERROR);
}
}
}