1、依赖
<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.18.1</version> </dependency>
2、JWT工具类
package com.jay.SpringBootStudy8.utils; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTCreator; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.DecodedJWT; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.Date; import java.util.HashMap; /** * Jwt工具类 */ public class JwtUtil { //自定密钥,最好搞长一点 public static final String tokenKey = "jay2021"; /* 生成票证 */ public static String getSign(HashMap<String,Object> headMap,HashMap<String,String> claimMap,int days){ LocalDateTime localDateTime = LocalDateTime.now().plus(days, ChronoUnit.DAYS); Date date = LocalDateTimeUtil.localDateTimeToDate(localDateTime); JWTCreator.Builder builder = JWT.create().withHeader(headMap); claimMap.forEach((key, value) -> { builder.withClaim(key, value); }); builder.withExpiresAt(date); String token = builder.sign(Algorithm.HMAC256(tokenKey)); return token; } /* 获取token信息,token不对会异常 */ public static DecodedJWT verify(String token){ DecodedJWT verify = JWT.require(Algorithm.HMAC256(tokenKey)).build().verify(token); return verify; } }
3、日期工具类LocalDateTimeUtil
package com.jay.SpringBootStudy8.utils; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Date; public class LocalDateTimeUtil { /** * LocalDateTime转毫秒时间戳 * @param localDateTime LocalDateTime * @return 时间戳 */ public static Long localDateTimeToTimestamp(LocalDateTime localDateTime) { try { ZoneId zoneId = ZoneId.systemDefault(); Instant instant = localDateTime.atZone(zoneId).toInstant(); return instant.toEpochMilli(); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 时间戳转LocalDateTime * @param timestamp 时间戳 * @return LocalDateTime */ public static LocalDateTime timestampToLocalDateTime(long timestamp) { try { Instant instant = Instant.ofEpochMilli(timestamp); ZoneId zone = ZoneId.systemDefault(); return LocalDateTime.ofInstant(instant, zone); } catch (Exception e) { e.printStackTrace(); } return null; } /** * Date转LocalDateTime * @param date Date * @return LocalDateTime */ public static LocalDateTime dateToLocalDateTime(Date date) { try { Instant instant = date.toInstant(); ZoneId zoneId = ZoneId.systemDefault(); return instant.atZone(zoneId).toLocalDateTime(); } catch (Exception e) { e.printStackTrace(); } return null; } /** * LocalDateTime转Date * @param localDateTime LocalDateTime * @return Date */ public static Date localDateTimeToDate(LocalDateTime localDateTime) { try { ZoneId zoneId = ZoneId.systemDefault(); ZonedDateTime zdt = localDateTime.atZone(zoneId); return Date.from(zdt.toInstant()); } catch (Exception e) { e.printStackTrace(); } return null; } }
4、JWT拦截器,在请求头的Authorization中携带token
package com.jay.SpringBootStudy8.config; import com.auth0.jwt.exceptions.AlgorithmMismatchException; import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.exceptions.TokenExpiredException; import com.auth0.jwt.interfaces.DecodedJWT; import com.fasterxml.jackson.databind.ObjectMapper; import com.jay.SpringBootStudy8.utils.JwtUtil; import org.springframework.web.servlet.HandlerInterceptor; import java.util.HashMap; public class JWTInterceptor implements HandlerInterceptor { @Override public boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler) throws Exception { HashMap<String,Object> res = new HashMap<>(); res.put("state",false); String authStr = request.getHeader("Authorization"); try { DecodedJWT verify = JwtUtil.verify(authStr); res.put("state",true); return true; }catch (SignatureVerificationException e) { e.printStackTrace();//无效签名 res.put("msg","无效签名"); }catch (TokenExpiredException e){ e.printStackTrace();//token过期 res.put("msg","token过期"); }catch (AlgorithmMismatchException e){ e.printStackTrace();//算法不一致 res.put("msg","算法不一致"); }catch (Exception e){ e.printStackTrace();//token无效 res.put("msg","token无效"); } String json = new ObjectMapper().writeValueAsString(res); response.setContentType("application/json;charset=UTF-8"); response.getWriter().println(json); return false; } }
5、注册拦截器
package com.jay.SpringBootStudy8.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class CustomerMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new JWTInterceptor()).addPathPatterns("/scanner/getCompanies"); } }
6、登录生成token、获取token信息、验证拦截器,登录使用的是Shiro
package com.jay.SpringBootStudy8.controller; import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.DecodedJWT; import com.jay.SpringBootStudy8.pojo.SysUser; import com.jay.SpringBootStudy8.utils.JwtUtil; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.crypto.hash.SimpleHash; import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.ByteSource; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; @RestController public class ScannerController { /* 登录,生成token */ @PostMapping("/scanner/login") public HashMap<String,Object> login(String name, String pwd) { HashMap<String,Object> res = new HashMap<>(); res.put("state",false); //MD5加密 ByteSource credentialsSalt = ByteSource.Util.bytes(name); Object obj = new SimpleHash("MD5", pwd, credentialsSalt, 1); String pwd2 = obj.toString(); //获取当前用户 Subject subject = SecurityUtils.getSubject(); //封装登录数据 UsernamePasswordToken token = new UsernamePasswordToken(name, pwd2); try { //执行登录方法 subject.login(token); Session session = subject.getSession(); SysUser user = (SysUser) session.getAttribute("user"); // 登录成功,生成票证 HashMap<String,Object> headMap = new HashMap<>(); HashMap<String,String> claimMap = new HashMap<>(); claimMap.put("userId",Integer.toString(user.getId())); claimMap.put("userName",user.getUserName()); String signStr = JwtUtil.getSign(headMap,claimMap,7); res.put("state",true); res.put("msg","登录成功"); res.put("token",signStr); } catch (UnknownAccountException e) { res.put("msg","用户名不存在"); } catch (IncorrectCredentialsException e) { res.put("msg","密码错误"); } return res; } /* 获取token信息 authStr 如果是这种格式 Bearer token 需要把Bearer和空格替掉。 */ @PostMapping("/scanner/checkToken") public Map<String, String> checkToken(@RequestHeader("Authorization")String authStr){ DecodedJWT verify = JwtUtil.verify(authStr); Map<String, Claim> claims = verify.getClaims(); Map<String,String> res = new HashMap<>(); claims.forEach((key,value)->{ res.put(key,value.asString()); }); return res; } /* 拦截请求 */ @PostMapping("/scanner/getCompanies") public Map<String,String> getCompanies(){ Map<String,String> res = new HashMap<>(); res.put("ali","阿里巴巴"); res.put("baidu","百度"); return res; } }
视频:https://www.bilibili.com/video/BV1i54y1m7cP?p=1