登录token

This commit is contained in:
Zhang Liguo 2023-12-21 22:39:29 +08:00
parent 1399bfd1e5
commit 9a0fa79bcb
9 changed files with 418 additions and 8 deletions

19
pom.xml
View File

@ -64,6 +64,25 @@
<artifactId>commons-lang</artifactId> <artifactId>commons-lang</artifactId>
<version>2.6</version> <version>2.6</version>
</dependency> </dependency>
<!--token包-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.6.0</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency> <dependency>
<groupId>com.alibaba.fastjson2</groupId> <groupId>com.alibaba.fastjson2</groupId>

View File

@ -1,43 +1,56 @@
package com.lovenav.controller; package com.lovenav.controller;
import com.alibaba.fastjson2.JSONObject;
import com.lovenav.entity.User; import com.lovenav.entity.User;
import com.lovenav.service.UserService; 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.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*; 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.servlet.http.HttpSession;
import javax.websocket.Session; import javax.websocket.Session;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
@RestController @RestController
public class UserController { public class UserController {
@Autowired @Autowired
UserService userService; UserService userService;
@Autowired
TokenUtils tokenUtils;
//发送邮箱验证码
@GetMapping("/sendActiveCode") @GetMapping("/sendActiveCode")
public String sendActiveCode(HttpSession session, User user){ public String sendActiveCode(HttpSession session, User user){
String activecode=userService.sendEmailActivecode(user); String activecode=userService.sendEmailActivecode(user);
session.setAttribute("realactivecode",activecode); session.setAttribute(user.getUserEmail(),activecode);
return "发送验证码成功!"; return "发送验证码成功!";
} }
@RequestMapping("/register") @RequestMapping("/register")
public String userRegister(HttpSession session,User user){ 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 "验证码不正确"; return "验证码不正确";
} }
System.out.println(user.getUserLogin()); System.out.println(user.getUserLogin());
System.out.println(user.getUserEmail()); System.out.println(user.getUserEmail());
// 用户注册之前根据用户名称查询该用户是否存在如果不存在的情况下才可以注册 如果存在的话就无法注册 // 用户注册之前根据用户名称查询该用户是否存在如果不存在的情况下才可以注册 如果存在的话就无法注册
User user1=userService.selectUserAlreadyExist(user); User user1=userService.selectUserAlreadyExist(user);
System.out.println("zhuce");
if (user1 != null) { if (user1 != null) {
return "用户名: " + user1.getUserEmail() + "已被注册!"; return "用户名: " + user1.getUserEmail() + "已被注册!";
} }
//用户数据注册 //用户数据注册
int register = userService.UserRegister(user); int register = userService.UserRegister(user);
if (register <= 0) { if (register <= 0) {
// 注册失败了 //转发到错误页面 // 注册失败了 //转发到错误页面
@ -45,5 +58,47 @@ public class UserController {
} }
return "注册成功!"; return "注册成功!";
} }
@RequestMapping("/login")
public Map<String,Object>login(User user,String code,HttpSession session){
Map<String,Object> 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();
}
}
} }

View File

@ -24,4 +24,5 @@ public interface UserDao {
User selectByUserLogin(String user_Login); User selectByUserLogin(String user_Login);
} }

View File

@ -4,10 +4,13 @@ import java.io.Serializable;
import java.util.Date; import java.util.Date;
import lombok.Data; import lombok.Data;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.bind.DefaultValue;
import org.springframework.stereotype.Component;
/** /**
* ln_user * ln_user
*/ */
@Data @Data
public class User implements Serializable { public class User implements Serializable {
/** /**
@ -146,7 +149,7 @@ public class User implements Serializable {
/** /**
* 角色组 * 角色组
*/ */
@Value("1")
private Byte roleId; private Byte roleId;
private String activeCode; private String activeCode;

View File

@ -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;
}
}

View File

@ -5,9 +5,12 @@ import com.lovenav.dao.UserDao;
import com.lovenav.utils.EmailUtils; import com.lovenav.utils.EmailUtils;
import com.lovenav.entity.User; import com.lovenav.entity.User;
import com.lovenav.service.UserService; import com.lovenav.service.UserService;
import com.lovenav.utils.MD5Utils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.regex.Pattern;
@Service @Service
public class UserServiceImpl implements UserService { public class UserServiceImpl implements UserService {
@ -20,6 +23,9 @@ public class UserServiceImpl implements UserService {
@Override @Override
public int UserRegister(User user) { 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); return userDao.insert(user);
} }
@ -33,8 +39,33 @@ public class UserServiceImpl implements UserService {
@Override @Override
public User userLogin(User user) { public User userLogin(User user) {
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; 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;
}
}
}
} }

View File

@ -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));
}
}

View File

@ -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<String, Object> header = new HashMap<String, Object>();
// 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;
}
}

View File

@ -155,7 +155,7 @@
select select
<include refid="Base_Column_List" /> <include refid="Base_Column_List" />
from ln_user from ln_user
where user_email = #{user_login,jdbcType=VARCHAR} where user_login = #{user_login,jdbcType=VARCHAR}
</select> </select>