通俗地讲就是验证当前用户的身份,证明“你是你自己”(比如:你每天上下班打卡,都需要通过指纹打卡,当你的指纹和系统里录入的指纹相匹配时,就打卡成功)互联网中的认证:
用户名密码登录邮箱发送登录链接手机号接收验证码只要你能收到邮箱/验证码,就默认你是账号的主人。
用户授予第三方应用访问该用户某些资源的权限。
如获得位置权限、头像权限、访问内存权限。
实现授权方式:cookie、token、session、Oauth
实现认证和授权的前提是需要一种媒介(证书) 来标记访问者的身份。
现实生活中如身份证,登录网站游客模式或用户模式。
服务器会给浏览器一个令牌token,用户拿到这个令牌才可以访问某些资源,如收藏、登录、点赞。
每次浏览器发送请求时会带上这个令牌,就可以使用游客模式下无法使用的功能。
http是无状态的协议,对事务处理没有记忆,每次客户端和服务端完成会话时,不会保存会话信息。
没法进行会话跟踪,无法确认这次访问者和上一次会话访问者的关系。
为了进行会话跟踪,确认状态需要session和cookie来维护。
Cookie:记录在客户端,服务器发送到客户端并存储到客户端。下一次访问会发送到服务端。不可跨域。
session是另一种记录浏览器端和服务器端会话状态的机制。
session存储在服务器端,sessionid会被存储到客户端的cookie中。
session 认证流程:
用户第一次请求服务器的时候,服务器根据用户提交的相关信息,创建对应的 Session请求返回时将此 Session 的唯一标识信息 SessionID 返回给浏览器浏览器接收到服务器返回的 SessionID 信息后,会将此信息存入到 Cookie 中,同时 Cookie 记录此 SessionID 属于哪个域名当用户第二次访问服务器的时候,请求会自动判断此域名下是否存在 Cookie 信息,如果存在自动将 Cookie 信息也发送给服务端,服务端会从 Cookie 中获取 SessionID,再根据 SessionID 查找对应的 Session 信息,如果没有找到说明用户没有登录或者登录失效,如果找到 Session 证明用户已经登录可执行后面操作。
根据以上流程可知,SessionID 是连接 Cookie 和 Session 的一道桥梁,大部分系统也是根据此原理来验证用户登录状态。
cookie和session的区别?
1.安全性:session更高。
2有效期:Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭(默认情况下)或者 Session 超时都会失效。
访问资源接口所需要的凭证。
简单token的构成:uid(身份标识)、当前时间、sign签名。
uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串)
客户端使用用户名跟密码请求登录服务端收到请求,去验证用户名与密码验证成功后,服务端会签发一个 token 并把这个 token 发送给客户端客户端收到 token 以后,会把它存储起来,比如放在 cookie 里或者 localStorage 里客户端每次向服务端请求资源的时候需要带着服务端签发的 token服务端收到请求,然后去验证客户端请求里面带着的 token ,如果验证成功,就向客户端返回请求的数据。
每一次请求都需要携带 token,需要把 token 放到 HTTP 的 Header 里基于 token 的用户认证是一种服务端无状态的认证方式,服务端不用存放 token 数据。用解析 token 的计算时间换取 session 的存储空间,从而减轻服务器的压力,减少频繁的查询数据库token 完全由应用管理,所以它可以避开同源策略
JWT(JSON WEB Token)是一个标准,借助JSON格式数据作为WEB应用请求中的令牌,进行数据的自包含设计,实现各方安全的信息传输,在数据传输过程中还可以对数据进行加密,签名等相关处理。同时JWT也是目前最流行的跨域身份验证解决方案(其官方网址为:https://jwt.io/)。可以非常方便的在分布式系统中实现用户身份认证。
JWT 认证流程:
用户输入用户名/密码登录,服务端认证成功后,会返回给客户端一个 JWT客户端将 token 保存到本地(通常使用 localstorage,也可以使用 cookie)当用户希望访问一个受保护的路由或者资源的时候,需要请求头的 Authorization 字段中使用Bearer 模式添加 JWT,其内容看起来是下面这样
JWT数据有Header(头部)、PayLoad(负载)、Signature(签名)。
Header部分:
Header 部分
是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子。
{
“alg”: “HS256”,
“typ”: “JWT”
}
Payload部分
Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT规范中规定了7个官方字段,供选用。
iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号
JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。
Signature部分
Signature 部分是对前两部分的签名,其目的是防止数据被篡改。
首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。
HMACSHA256(
base64UrlEncode(header) + “.” +
base64UrlEncode(payload),
secret)
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。
一 所加依赖
io.jsonwebtoken
jjwt
0.9.1
二创建和解析token
@Test
void testCreateAndParseToken(){
//1.创建令牌
//1.1定义负载信息
Map
map.put(“username”, “jack”);
map.put(“permissions”, “sys:res:create,sys:res:retrieve”);
//1.2定义过期实践
Calendar calendar=Calendar.getInstance();
calendar.add(Calendar.MINUTE, 30);
Date expirationTime=calendar.getTime();
//1.3定义密钥
String secret=“AAABBBCCCDDD”;
//1.4生成令牌
String token= Jwts.builder()
.setClaims(map)
.setIssuedAt(new Date())
.setExpiration(calendar.getTime())
.signWith(SignatureAlgorithm.HS256,secret)
.compact();
System.out.println(token);
//2.解析令牌
Claims claims = Jwts.parser().setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
System.out.println(“claims=”+claims);
}
创建JWT工具类
为了简化JWT在项目中的应用,我们通常会构建一个工具类,对token的创建和解析进行封装,例如:
package com.cy.jt.security.util;
public class JwtUtils {
/**
* 秘钥
/
private static String secret=“AAABBBCCCDDDEEE”;
/*
* 有效期,单位秒
* 默认30分钟
*/
private static Long expirationTimeInSecond=1800L;
/**
* 从token中获取claim
*
* @param token token
* @return claim
*/
public static Claims getClaimsFromToken(String token) {
try {
return Jwts.parser()
.setSigningKey(secret.getBytes())
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
throw new IllegalArgumentException("Token invalided.");
}
}
/**
* 判断token是否过期
* @param token token
* @return 已过期返回true,未过期返回false
*/
private static Boolean isTokenExpired(String token) {
Date expiration = getClaimsFromToken(token).getExpiration();
return expiration.before(new Date());
}
/**
* 为指定用户生成token
* @param claims 用户信息
* @return token
*/
public static String generateToken(Map claims) {
Date createdTime = new Date();
Date expirationTime = new Date(System.currentTimeMillis() + expirationTimeInSecond * 1000);
return Jwts.builder()
.setClaims(claims)
.setIssuedAt(createdTime)
.setExpiration(expirationTime)
.signWith(SignatureAlgorithm.HS256,secret)
.compact();
}
}
假如在每个方法中都去校验用户身份的合法性,代码冗余会比较大,我们可以写一个Spring MVC 拦截器,
在拦截器中进行用户身份检测,例如:
一 所用的API
HandlerInterceptor \WebMvcConfigurer.
Jwts
第一步:
创建一个拦截器:
package com.cy.jt.security.interceptor;
import com.cy.jt.security.util.JwtUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
1、JWT产生背景
2、相关概念掌握:token session cookie jwt
3、token/jwt 解析步骤 --》创建令牌 解析令牌,存储过程
4、相关API的使用,如JWTS\拦截器、配置类要配置等等。