From 9efaa513f2f8dddba544b194988e9e1079adc06a Mon Sep 17 00:00:00 2001 From: Zhang Liguo <482370576@qq.com> Date: Sat, 23 Dec 2023 16:23:38 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8B=A6=E6=88=AA=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 52 ++++- .../configuration/MyWebConfigurer.java | 2 +- .../lovenav/controller/UserController.java | 35 ++-- .../com/lovenav/filter/UserInterceptor.java | 44 +++-- .../service/serviceImpl/UserServiceImpl.java | 1 + .../java/com/lovenav/utils/TokenUtils.java | 185 +++++++++--------- src/main/resources/application.yml | 14 +- 7 files changed, 200 insertions(+), 133 deletions(-) diff --git a/pom.xml b/pom.xml index 7010b1e..aa0b2c6 100644 --- a/pom.xml +++ b/pom.xml @@ -60,17 +60,50 @@ 2.6 + + + com.google.guava + guava + 31.0.1-jre + + + + com.auth0 + java-jwt + 3.4.0 + + + + + org.projectlombok + lombok + 1.18.22 + + + + + com.alibaba + druid + 1.2.6 + - com.auth0 - java-jwt - 3.5.0 + io.jsonwebtoken + jjwt-api + 0.11.5 io.jsonwebtoken - jjwt - 0.6.0 + jjwt-impl + 0.11.5 + + io.jsonwebtoken + jjwt-jackson + 0.11.5 + + + @@ -202,6 +235,15 @@ + + + + + + + + + diff --git a/src/main/java/com/lovenav/configuration/MyWebConfigurer.java b/src/main/java/com/lovenav/configuration/MyWebConfigurer.java index b13b3a7..f366cba 100644 --- a/src/main/java/com/lovenav/configuration/MyWebConfigurer.java +++ b/src/main/java/com/lovenav/configuration/MyWebConfigurer.java @@ -8,7 +8,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; public class MyWebConfigurer implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { -// registry.addInterceptor(new UserInterceptor()).addPathPatterns("/*/**").excludePathPatterns("/error","/login","/register","/findThePassword","/verifyCode","/sendActiveCode"); + registry.addInterceptor(new UserInterceptor()).addPathPatterns("/*/**").excludePathPatterns("/error","/login","/register","/findThePassword","/verifyCode","/sendActiveCode"); WebMvcConfigurer.super.addInterceptors(registry); } } diff --git a/src/main/java/com/lovenav/controller/UserController.java b/src/main/java/com/lovenav/controller/UserController.java index 4c42103..a488015 100644 --- a/src/main/java/com/lovenav/controller/UserController.java +++ b/src/main/java/com/lovenav/controller/UserController.java @@ -81,41 +81,42 @@ public class UserController { } @RequestMapping(value = "/login",produces = {"application/json;charset=UTF-8"}) public Maplogin(User user,String code,HttpSession session){ + Map result=new HashMap<>(); Map map=new HashMap<>(); String sessionCode = (String) session.getAttribute(RandomValidateCode.RANDOMVALIDATECODE); if (sessionCode==null){ - map.put("msg","验证码空的"); - return map; + result.put("msg","验证码空的"); + return result; } if (!sessionCode.equals(code)){ - map.put("msg","验证码错误"); - return map; + result.put("msg","验证码错误"); + return result; } if(StringUtils.isEmpty(user.getUserLogin())||StringUtils.isEmpty(user.getUserPassword())){ - map.put("msg","用户或密码为空!"); - return map; + result.put("msg","用户或密码为空!"); + return result; } User user1 = userService.userLogin(user); if(user1!=null){ - map.put("code",200); - String token= tokenUtils.sign(user1); + result.put("code",200); map.put("userEmail",user1.getUserEmail()); map.put("userLogin",user1.getUserLogin()); - map.put("user",user1.getUserEmail()); - map.put("userStatus",user1.getUserStatus()); - map.put("Id",user1.getId()); - map.put("nickname",user1.getNickname()); - map.put("roleId",user1.getRoleId()); - map.put("userRegistered",user1.getUserRegistered()); - map.put("token",token); + String token= TokenUtils.createJWT(map,10000000L); + result.put("user",user1.getUserEmail()); + result.put("userStatus",user1.getUserStatus()); + result.put("Id",user1.getId()); + result.put("nickname",user1.getNickname()); + result.put("roleId",user1.getRoleId()); + result.put("userRegistered",user1.getUserRegistered()); + result.put("token",token); }else { - map.put("msg","用户名或密码错误!"); + result.put("msg","用户名或密码错误!"); } - return map; + return result; } /*图片验证码*/ @RequestMapping("/verifyCode") diff --git a/src/main/java/com/lovenav/filter/UserInterceptor.java b/src/main/java/com/lovenav/filter/UserInterceptor.java index 5a8d224..88cf02f 100644 --- a/src/main/java/com/lovenav/filter/UserInterceptor.java +++ b/src/main/java/com/lovenav/filter/UserInterceptor.java @@ -2,22 +2,29 @@ package com.lovenav.filter; import com.alibaba.fastjson.JSON; +import com.auth0.jwt.exceptions.AlgorithmMismatchException; +import com.auth0.jwt.exceptions.SignatureVerificationException; +import com.auth0.jwt.exceptions.TokenExpiredException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.lovenav.utils.TokenUtils; import io.jsonwebtoken.Claims; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; +import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.io.IOException; import java.util.HashMap; import java.util.Map; - +@Configuration public class UserInterceptor implements HandlerInterceptor { //Controller逻辑执行之前 - @Autowired +@Autowired private TokenUtils tokenUtils; public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object obj, Exception e) @@ -31,29 +38,36 @@ public class UserInterceptor implements HandlerInterceptor { } // 拦截每个请求 - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object obj) { + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object obj) throws IOException { Map map=new HashMap<>(); System.out.println("开始进入拦截器检验jwt头部是否含有Authorization方法!"); // 通过url得到token请求头是否包含Authorization response.setCharacterEncoding("UTF-8"); String jwt = request.getHeader("Authorization"); - System.out.println(jwt); + if (jwt==null){ + map.put("msg","请求头中不含token"); + response.getWriter().print(JSON.toJSONString(map)); + return false; + } try { + Claims c = TokenUtils.verifyJwt(jwt); + return true; // 检测请求头是否为空 - if (jwt == null) { - System.out.println("用户未登录,验证失败"); - map.put("msg","用户未登录,验证失败"); - response.getWriter().print(JSON.toJSONString(map)); - return false; - } else { - Claims c = tokenUtils.parseJWT(jwt); - System.out.println("用户[ " + c.get("userLogin") + " ]已是登录状态"); - System.out.println("结束进入拦截器检验jwt头部是否含有Authorization方法!"); - return true; - } + } catch (TokenExpiredException e) { + map.put("state", false); + map.put("msg", "Token已经过期!!!"); + } catch (SignatureVerificationException e){ + map.put("state", false); + map.put("msg", "签名错误!!!"); + } catch (AlgorithmMismatchException e){ + map.put("state", false); + map.put("msg", "加密算法不匹配!!!"); } catch (Exception e) { e.printStackTrace(); + map.put("state", false); + map.put("msg", "无效token"); } + response.getWriter().print(JSON.toJSONString(map)); return false; } diff --git a/src/main/java/com/lovenav/service/serviceImpl/UserServiceImpl.java b/src/main/java/com/lovenav/service/serviceImpl/UserServiceImpl.java index 25c3a4c..7528b37 100644 --- a/src/main/java/com/lovenav/service/serviceImpl/UserServiceImpl.java +++ b/src/main/java/com/lovenav/service/serviceImpl/UserServiceImpl.java @@ -32,6 +32,7 @@ public class UserServiceImpl implements UserService { return null; } else if (user1.getUserPassword().equals(user.getUserPassword())){ + return user1; }else { return null; diff --git a/src/main/java/com/lovenav/utils/TokenUtils.java b/src/main/java/com/lovenav/utils/TokenUtils.java index 00eb4a5..0a0fc88 100644 --- a/src/main/java/com/lovenav/utils/TokenUtils.java +++ b/src/main/java/com/lovenav/utils/TokenUtils.java @@ -1,125 +1,122 @@ package com.lovenav.utils; -import com.auth0.jwt.JWT; -import com.auth0.jwt.JWTVerifier; -import com.auth0.jwt.algorithms.Algorithm; -import com.auth0.jwt.exceptions.JWTDecodeException; -import com.auth0.jwt.interfaces.DecodedJWT; -import com.lovenav.entity.User; -import com.lovenav.service.UserService; - - - -import io.jsonwebtoken.*; -import org.apache.tomcat.util.codec.binary.Base64; -import org.springframework.beans.factory.annotation.Autowired; +import com.google.common.io.BaseEncoding; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.JwtBuilder; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; -import org.springframework.stereotype.Service; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.util.Date; import java.util.HashMap; import java.util.Map; -import java.util.UUID; @Component public class TokenUtils { + private static long tokenExpiredTime; - private static final long EXPIRE_TIME = 60 * 1000; // 1分钟 -// private static final long EXPIRE_TIME = 15 * 60 * 1000; // 15分钟 + private static String jwtId; - // 加密密文,私钥 - private static final String TOKEN_SECRET = "jiamimiwen"; + private static String jwtSecret; - // 由字符串生成加密key - public SecretKey generalKey() { - System.out.println("进入由字符串生成加密key方法!"); - // 本地的密码解码 - byte[] encodedKey = Base64.decodeBase64(TOKEN_SECRET); - // 根据给定的字节数组使用AES加密算法构造一个密钥 - SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES"); - return key; + /** + * 创建JWT + */ + public static String createJWT(Map claims, Long time) { + //指定签名的时候使用的签名算法,也就是header那部分,jjwt已经将这部分内容封装好了。 + SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; + Date now = new Date(System.currentTimeMillis()); + + SecretKey secretKey = generalKey(); + //生成JWT的时间 + long nowMillis = System.currentTimeMillis(); + //下面就是在为payload添加各种标准声明和私有声明了 + //这里其实就是new一个JwtBuilder,设置jwt的body + JwtBuilder builder = Jwts.builder() + //如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的 + .setClaims(claims) + //设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。 + .setId(jwtId) + //iat: jwt的签发时间 + .setIssuedAt(now) + //设置签名使用的签名算法和签名使用的秘钥 + .signWith(signatureAlgorithm, secretKey); + if (time >= 0) { + long expMillis = nowMillis + time; + Date exp = new Date(expMillis); + //设置过期时间 + builder.setExpiration(exp); + } + return builder.compact(); } - // 生成签名 - public String sign(User user) { - System.out.println("生成签名方法开始执行!"); + + /** + * 验证jwt + */ + public static Claims verifyJwt(String token) { + //签名秘钥,和生成的签名的秘钥一模一样 + SecretKey key = generalKey(); + Claims claims; try { - // 设置过期时间,单位毫秒 - Date expTime = new Date(System.currentTimeMillis() + EXPIRE_TIME); - // 私钥和加密算法 - Algorithm algorithm = Algorithm.HMAC256(user.getUserPassword()); //使用用户输入的密码 -// Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET); - // 设置头部信息,也可以不用设置头部信息jwt会自动生成 -// Map header = new HashMap(); -// header.put("typ", "JWT"); -// header.put("alg", "HS256"); - // 或 - // header.put("Type", "JWT"); - // header.put("alg", "HS256"); - // 生成JWT的时间 - Date issuedAt = new Date(System.currentTimeMillis()); - // 返回token字符串 - System.out.println("生成签名方法结束执行!"); - return JWT.create() // 表示new一个Jwt,设置jwt的body -// .withHeader(header) // 设置头部信息 - .withClaim("userLogin", user.getUserLogin()) // 数据库中用户的id - .withClaim("email", user.getUserEmail()) // 前端输入的用户名 - .withIssuedAt(issuedAt) // jwt的签发时间 - .withExpiresAt(expTime) // jwt过期时间 - .sign(algorithm); + claims = Jwts.parser() //得到DefaultJwtParser + .setSigningKey(key) //设置签名的秘钥 + .parseClaimsJws(token).getBody(); } catch (Exception e) { - e.printStackTrace(); - return null; - } + claims = null; + }//设置需要解析的jwt + return claims; + } /** + * 由字符串生成加密key * - * @Title: verify - * @Description: 检验token是否正确 - * @param: @param token 密钥 - * @param: @param username 登录名 - * @param: @param password 密码 - * @param: @return - * @return: boolean - * @throws + * @return SecretKey */ - public boolean verify(String token, String username, String password) { - System.out.println("进入检验token是否正确方法!"); - try { - Algorithm algorithm = Algorithm.HMAC256(password); //使用用户输入的密码 -// Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET); - JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build(); -// JWTVerifier verifier = JWT.require(algorithm).build(); - verifier.verify(token); - return true; - } catch (Exception e) { - return false; - } + public static SecretKey generalKey() { + String stringKey = jwtSecret; + byte[] encodedKey = BaseEncoding.base64().decode(stringKey); + SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "HmacSHA256"); + return key; } - // 获取登录名 - public String getUsername(String token) { - System.out.println("进入获取登录名方法!"); - try { - DecodedJWT jwt = JWT.decode(token); - return jwt.getClaim("username").asString(); - } catch (JWTDecodeException e) { - return null; - } + /** + * 根据userId和openid生成token + */ + public static String generateToken(String openId) { + Map map = new HashMap<>(); + map.put("openId", openId); + return createJWT(map, tokenExpiredTime); } - // 解密jwt - public Claims parseJWT(String jwt) throws Exception { - System.out.println("进入解密jwt方法!"); - SecretKey key = generalKey(); // 签名秘钥,和生成的签名的秘钥一模一样 - Claims claims = Jwts.parser() // 得到DefaultJwtParser - .setSigningKey(key) // 设置签名的秘钥 - .parseClaimsJws(jwt).getBody(); // 设置需要解析的jwt - return claims; + @Value("${jwt.token-expired-time}") + public void setTokenExpiredTime(long tokenExpiredTime) { + TokenUtils.tokenExpiredTime = tokenExpiredTime; } + @Value("${jwt.id}") + public void setJwtId(String jwtId) { + TokenUtils.jwtId = jwtId; + } -} + @Value("${jwt.secret}") + public void setJwtSecret(String jwtSecret) { + TokenUtils.jwtSecret = jwtSecret; + } + + public static long getTokenExpiredTime() { + return tokenExpiredTime; + } + + public static String getJwtId() { + return jwtId; + } + + public static String getJwtSecret() { + return jwtSecret; + } +} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 1ee784d..332ae23 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -2,7 +2,7 @@ spring: datasource: url: jdbc:mysql://localhost:3306/love-nav username: root - password: 1611 + password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver redis: host: localhost @@ -16,6 +16,18 @@ spring: min-idle: 0 max-wait: -1 timeout: 10000 +mybatis: + type-aliases-package: com.lovenav.entity + mapper-locations: classpath:mybatis/*.xml + +jwt: + #设置token的过期时间,单位为秒 + token-expired-time: 36000 #10小时 + #设置token的id + id: tokenId + #设置密钥 + secret: aPbOBbnH4gnZBzIYEY7mxWNu49kYljNPMeva9Fjrwwqzw0bFlO0kPXZTCGaVcw0j +#