diff --git a/pom.xml b/pom.xml index 73de8d7..a5b2ed7 100644 --- a/pom.xml +++ b/pom.xml @@ -64,6 +64,25 @@ commons-lang 2.6 + + + + com.auth0 + java-jwt + 3.5.0 + + + io.jsonwebtoken + jjwt + 0.6.0 + + + + + com.alibaba + fastjson + 1.2.47 + com.alibaba.fastjson2 diff --git a/src/main/java/com/lovenav/controller/UserController.java b/src/main/java/com/lovenav/controller/UserController.java index fb1132a..8e18a2d 100644 --- a/src/main/java/com/lovenav/controller/UserController.java +++ b/src/main/java/com/lovenav/controller/UserController.java @@ -1,43 +1,56 @@ package com.lovenav.controller; +import com.alibaba.fastjson2.JSONObject; import com.lovenav.entity.User; import com.lovenav.service.UserService; +import com.lovenav.utils.MD5Utils; +import com.lovenav.utils.RandomValidateCode; +import com.lovenav.utils.TokenUtils; +import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.websocket.Session; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Map; @RestController public class UserController { @Autowired UserService userService; + @Autowired + TokenUtils tokenUtils; + //发送邮箱验证码 @GetMapping("/sendActiveCode") public String sendActiveCode(HttpSession session, User user){ String activecode=userService.sendEmailActivecode(user); - session.setAttribute("realactivecode",activecode); + session.setAttribute(user.getUserEmail(),activecode); return "发送验证码成功!"; } @RequestMapping("/register") public String userRegister(HttpSession session,User user){ - // 比较验证码 - if (!user.getActiveCode().equalsIgnoreCase((String) session.getAttribute("realactivecode"))) { + if (!user.getActiveCode().equals((String) session.getAttribute(user.getUserEmail()))) { return "验证码不正确"; } System.out.println(user.getUserLogin()); System.out.println(user.getUserEmail()); // 用户注册之前根据用户名称查询该用户是否存在如果不存在的情况下才可以注册 如果存在的话就无法注册 User user1=userService.selectUserAlreadyExist(user); - System.out.println("zhuce"); - if (user1 != null) { return "用户名: " + user1.getUserEmail() + "已被注册!"; } //用户数据注册 + int register = userService.UserRegister(user); if (register <= 0) { // 注册失败了 //转发到错误页面 @@ -45,5 +58,47 @@ public class UserController { } return "注册成功!"; } + @RequestMapping("/login") + public Maplogin(User user,String code,HttpSession session){ + Map map=new HashMap<>(); + String sessionCode = (String) session.getAttribute(RandomValidateCode.RANDOMVALIDATECODE); + if (!sessionCode.equals(code)){ + map.put("msg","验证码错误"); + return map; + } + map.put("code",0); + if(StringUtils.isEmpty(user.getUserLogin())||StringUtils.isEmpty(user.getUserPassword())){ + map.put("msg","用户或密码为空!"); + return map; + } + + User user1 = userService.userLogin(user); + + if(user1!=null){ + + String token= tokenUtils.sign(user1); + map.put("cod",1); + map.put("data",user1); + map.put("token",token); + }else { + map.put("msg","用户名或密码错误!"); + } + return map; +} +/*图片验证码*/ + @RequestMapping("/verifyCode") + public void verifyCode(HttpServletRequest request,HttpServletResponse response){ + response.setContentType("image/jpeg");//设置相应类型,告诉浏览器输出的内容为图片 + response.setHeader("Pragma", "No-cache");//设置响应头信息,告诉浏览器不要缓存此内容 + response.setDateHeader("Expire", 0); + RandomValidateCode randomValidateCode = new RandomValidateCode(); + try { + randomValidateCode.getRandcode( request, response);//输出图片方法 + } catch (Exception e) { + e.printStackTrace(); + } + + } + } diff --git a/src/main/java/com/lovenav/dao/UserDao.java b/src/main/java/com/lovenav/dao/UserDao.java index 71352ba..8bd3d40 100644 --- a/src/main/java/com/lovenav/dao/UserDao.java +++ b/src/main/java/com/lovenav/dao/UserDao.java @@ -24,4 +24,5 @@ public interface UserDao { User selectByUserLogin(String user_Login); + } \ No newline at end of file diff --git a/src/main/java/com/lovenav/entity/User.java b/src/main/java/com/lovenav/entity/User.java index 9e88c02..613d8b2 100644 --- a/src/main/java/com/lovenav/entity/User.java +++ b/src/main/java/com/lovenav/entity/User.java @@ -4,10 +4,13 @@ import java.io.Serializable; import java.util.Date; import lombok.Data; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.bind.DefaultValue; +import org.springframework.stereotype.Component; /** * ln_user */ + @Data public class User implements Serializable { /** @@ -146,7 +149,7 @@ public class User implements Serializable { /** * 角色组 */ - @Value("1") + private Byte roleId; private String activeCode; diff --git a/src/main/java/com/lovenav/filter/LoginInterceptor.java b/src/main/java/com/lovenav/filter/LoginInterceptor.java new file mode 100644 index 0000000..c36fd0f --- /dev/null +++ b/src/main/java/com/lovenav/filter/LoginInterceptor.java @@ -0,0 +1,56 @@ +package com.lovenav.filter; + + +import com.lovenav.utils.TokenUtils; +import io.jsonwebtoken.Claims; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +public class LoginInterceptor implements HandlerInterceptor { + + + //Controller逻辑执行之前 + @Autowired + private TokenUtils tokenUtils; + + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object obj, Exception e) + throws Exception { + + } + + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object obj, ModelAndView mav) + throws Exception { + + } + + // 拦截每个请求 + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object obj) { + System.out.println("开始进入拦截器检验jwt头部是否含有Authorization方法!"); + // 通过url得到token请求头是否包含Authorization + String jwt = request.getHeader("Authorization"); + System.out.println(jwt); + try { + // 检测请求头是否为空 + if (jwt == null) { + System.out.println("用户未登录,验证失败"); + } else { + Claims c = tokenUtils.parseJWT(jwt); + System.out.println("用户[ " + c.get("username") + " ]已是登录状态"); + System.out.println("结束进入拦截器检验jwt头部是否含有Authorization方法!"); + return true; + } + System.out.println("token解析错误,验证失败"); + response.getWriter().write("未登录,请重新登录后操作"); + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + +} \ No newline at end of file diff --git a/src/main/java/com/lovenav/service/serviceImpl/UserServiceImpl.java b/src/main/java/com/lovenav/service/serviceImpl/UserServiceImpl.java index c0917c8..d8b4b0e 100644 --- a/src/main/java/com/lovenav/service/serviceImpl/UserServiceImpl.java +++ b/src/main/java/com/lovenav/service/serviceImpl/UserServiceImpl.java @@ -5,9 +5,12 @@ import com.lovenav.dao.UserDao; import com.lovenav.utils.EmailUtils; import com.lovenav.entity.User; import com.lovenav.service.UserService; +import com.lovenav.utils.MD5Utils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.regex.Pattern; + @Service public class UserServiceImpl implements UserService { @@ -20,6 +23,9 @@ public class UserServiceImpl implements UserService { @Override public int UserRegister(User user) { + user.setRoleId(Byte.valueOf("1")); + user.setUserStatus(Byte.valueOf("1")); + user.setUserPassword(MD5Utils.md5(user.getUserPassword())); return userDao.insert(user); } @@ -33,7 +39,32 @@ public class UserServiceImpl implements UserService { @Override public User userLogin(User user) { - return null; + boolean result; + User user1; + result= Pattern.matches("^(\\w+([-.][A-Za-z0-9]+)*){3,18}@\\w+([-.][A-Za-z0-9]+)*\\.\\w+([-.][A-Za-z0-9]+)*$", user.getUserLogin()); + if (result == true) { + user1= userDao.selectByEmail(user.getUserLogin()); + if (user1==null){ + return null; + } + else if (user1.getUserPassword().equals(user.getUserPassword())){ + return user1; + }else { + return null; + } + }else { + user1=userDao.selectByUserLogin(user.getUserLogin()); + + if (user1==null ){ + return null; + } + else if (user1.getUserPassword().equals(user.getUserPassword())){ + return user1; + }else { + return null; + } + + } } diff --git a/src/main/java/com/lovenav/utils/RandomValidateCode.java b/src/main/java/com/lovenav/utils/RandomValidateCode.java new file mode 100644 index 0000000..074bb20 --- /dev/null +++ b/src/main/java/com/lovenav/utils/RandomValidateCode.java @@ -0,0 +1,120 @@ +package com.lovenav.utils; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.Random; + +/** + * 工具类: 生成随机验证码 + */ +public class RandomValidateCode { + public static final String RANDOMVALIDATECODE = "RandomValidateCode";// 放到session中的key + private Random random = new Random(); + private String randString = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生的字符串 + private int width = 80;// 图片宽度 + private int height = 26;// 图片高度 + private int lineSize = 40;// 干扰线数量 + private int stringNum = 4;// 随机产生的字符数量 + + /** + * 获得字体 + */ + private Font getFont() { + return new Font("Fixedsys", Font.CENTER_BASELINE, 18); + } + + /** + * 获得颜色 + * + * @param bc + * @param fc + */ + private Color getRandColor(int fc, int bc) { + if (fc > 255) + fc = 255; + if (bc > 255) + bc = 255; + int r = fc + random.nextInt(bc - fc - 16); + int g = fc + random.nextInt(bc - fc - 14); + int b = fc + random.nextInt(bc - fc - 18); + return new Color(r, g, b); + } + + /** + * 生成随机图片 + * + * @param request + * @param response + */ + public void getRandcode(HttpServletRequest request, HttpServletResponse response) { + HttpSession session = request.getSession(); + // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类 + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR); + Graphics g = image.getGraphics();// 产生Image对象的Graphics对象,该对象可以在图像上进行各种绘制操作 + g.fillRect(0, 0, width, height); + g.setFont(new Font("Times New Roman", Font.ROMAN_BASELINE, 18)); + g.setColor(getRandColor(110, 133)); + // 绘制干扰线 + for (int i = 0; i <= lineSize; i++) { + drowLine(g); + } + // 绘制随机字符 + String randomString = ""; + for (int i = 1; i <= stringNum; i++) { + randomString = drowString(g, randomString, i); + } + request.getSession(true); + session.removeAttribute(RANDOMVALIDATECODE); + session.setAttribute(RANDOMVALIDATECODE, randomString); + g.dispose(); + try { + ImageIO.write(image, "JPEG", response.getOutputStream());// 将内存中的图片通过流动形式输出到客户端 + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 绘制字符串 + * + * @param g + * @param randomString + * @param i + */ + private String drowString(Graphics g, String randomString, int i) { + g.setFont(getFont()); + g.setColor(new Color(random.nextInt(101), random.nextInt(111), random.nextInt(121))); + String rand = getRandomString(random.nextInt(randString.length())); + randomString += rand; + g.translate(random.nextInt(3), random.nextInt(3)); + g.drawString(rand, 13 * i, 16); + return randomString; + } + + /** + * 绘制干扰线 + * + * @param g + */ + private void drowLine(Graphics g) { + int x = random.nextInt(width); + int y = random.nextInt(height); + int xl = random.nextInt(13); + int yl = random.nextInt(15); + g.drawLine(x, y, x + xl, y + yl); + } + + /** + * 获取随机的字符 + * + * @param num + */ + public String getRandomString(int num) { + return String.valueOf(randString.charAt(num)); + } +} diff --git a/src/main/java/com/lovenav/utils/TokenUtils.java b/src/main/java/com/lovenav/utils/TokenUtils.java new file mode 100644 index 0000000..00eb4a5 --- /dev/null +++ b/src/main/java/com/lovenav/utils/TokenUtils.java @@ -0,0 +1,125 @@ +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 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 final long EXPIRE_TIME = 60 * 1000; // 1分钟 +// private static final long EXPIRE_TIME = 15 * 60 * 1000; // 15分钟 + + // 加密密文,私钥 + private static final String TOKEN_SECRET = "jiamimiwen"; + + // 由字符串生成加密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; + } + + // 生成签名 + public String sign(User user) { + System.out.println("生成签名方法开始执行!"); + 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); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * + * @Title: verify + * @Description: 检验token是否正确 + * @param: @param token 密钥 + * @param: @param username 登录名 + * @param: @param password 密码 + * @param: @return + * @return: boolean + * @throws + */ + 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 String getUsername(String token) { + System.out.println("进入获取登录名方法!"); + try { + DecodedJWT jwt = JWT.decode(token); + return jwt.getClaim("username").asString(); + } catch (JWTDecodeException e) { + return null; + } + } + + // 解密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; + } + + +} diff --git a/src/main/resources/mybatis/UserDao.xml b/src/main/resources/mybatis/UserDao.xml index a32e907..36a485e 100644 --- a/src/main/resources/mybatis/UserDao.xml +++ b/src/main/resources/mybatis/UserDao.xml @@ -155,7 +155,7 @@ select from ln_user - where user_email = #{user_login,jdbcType=VARCHAR} + where user_login = #{user_login,jdbcType=VARCHAR}