1. 解析JWT时可能出现的错误
如果使用过期的JWT,在解析时将出现错误:
io.jsonwebtoken.ExpiredJwtException: JWT expired at 2022-09-06T17:33:03Z. Current time: 2022-09-08T09:04:26Z, a difference of 142283930 milliseconds. Allowed clock skew: 0 milliseconds.
如果使用的JWT数据的签名有误,在解析时将出现错误:
io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
如果使用的JWT数据格式有误,在解析时将出现错误:
io.jsonwebtoken.MalformedJwtException: Unable to read JSON value: {"alg !L��؈�������)]P�
后续,将需要对这3种异常进行捕获并处理!
2. 使用JWT实现认证
在使用Spring Security框架处理认证时,如果认证通过,必须把通过认证的用户的信息存入到SecurityContext
(Spring Security框架的上下文)对象中,后续,Spring Security框架会自动的尝试从SecurityContext
中获取认证信息,如果获取到有效的认证信息,则视为“已登录”,否则,将视为“未登录”!
使用JWT实现认证需要完成的开发任务:
- 当认证通过时生成JWT,并将JWT响应到客户端
- 当客户端后续提交请求时,应该自觉携带JWT,而服务器端将对JWT进行解析,如果解析成功,将得此客户端的用户信息,并将认证信息存入到
SecurityContext
中
3. 当认证通过时生成JWT,并将JWT响应到客户端
首先,需要修改IAdminService
中处理认证的方法(login()
方法)的声明,将返回值类型修改为String
:
String login(AdminLoginInfoDTO adminLoginInfoDTO);
并且,AdminServiceImpl
中方法的声明也同步修改,在实现过程中,当通过认证后,应该生成JWT并返回:
@Override
public String login(AdminLoginInfoDTO adminLoginInfoDTO) {
log.debug("开始处理【登录认证】的业务,参数:{}", adminLoginInfoDTO);
// 调用AuthenticationManager的authenticate()方法执行认证
// 在authenticate()方法的执行过程中
// Spring Security会自动调用UserDetailsService对象的loadUserByUsername()获取用户详情
// 并根据loadUserByUsername()返回的用户详情自动验证是否启用、判断密码是否正确等
Authentication authentication
= new UsernamePasswordAuthenticationToken(
adminLoginInfoDTO.getUsername(),
adminLoginInfoDTO.getPassword());
Authentication authenticateResult
= authenticationManager.authenticate(authentication);
log.debug("Spring Security已经完成认证,且认证通过,返回的结果:{}", authenticateResult);
log.debug("返回认证信息中的当事人(Principal)类型:{}", authenticateResult.getPrincipal().getClass().getName());
log.debug("返回认证信息中的当事人(Principal)数据:{}", authenticateResult.getPrincipal());
// 从认证返回结果中取出当事人信息
User principal = (User) authenticateResult.getPrincipal();
String username = principal.getUsername();
log.debug("认证信息中的用户名:{}", username);
// 生成JWT,并返回
// 准备Claims值
Map<String, Object> claims = new HashMap<>();
claims.put("username", username);
// JWT的过期时间
Date expiration = new Date(System.currentTimeMillis() + 15 * 24 * 60 * 60