一.环境准备
1.导入依赖
<!-- JWT生成Token-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
2.配置json 返回日期格式
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
3.验证码的工具类
public class CreateVerifiCodeImage {
private static int WIDTH = 90;
private static int HEIGHT = 35;
private static int FONT_SIZE = 20; //字符大小
private static char[] verifiCode; //验证码
private static BufferedImage verifiCodeImage; //验证码图片
/**
* @description: 获取验证码图片
* @param: no
* @return: java.awt.image.BufferedImage
*/
public static BufferedImage getVerifiCodeImage() {
verifiCodeImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_BGR);// create a image
Graphics graphics = verifiCodeImage.getGraphics();
verifiCode = generateCheckCode();
drawBackground(graphics);
drawRands(graphics, verifiCode);
graphics.dispose();
return verifiCodeImage;
}
/**
* @description: 获取验证码
* @param: no
* @return: char[]
*/
public static char[] getVerifiCode() {
return verifiCode;
}
/**
* @description: 随机生成验证码
* @param: no
* @return: char[]
*/
private static char[] generateCheckCode() {
String chars = "0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char[] rands = new char[4];
for (int i = 0; i < 4; i++) {
int rand = (int) (Math.random() * (10 + 26 * 2));
rands[i] = chars.charAt(rand);
}
return rands;
}
/**
* @description: 绘制验证码
* @param: g
* @param: rands
* @return: void
*/
private static void drawRands(Graphics g, char[] rands) {
g.setFont(new Font("Console", Font.BOLD, FONT_SIZE));
for (int i = 0; i < rands.length; i++) {
g.setColor(getRandomColor());
g.drawString("" + rands[i], i * FONT_SIZE + 10, 25);
}
}
/**
* @description: 绘制验证码图片背景
* @param: g
* @return: void
*/
private static void drawBackground(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, WIDTH, HEIGHT);
// 绘制验证码干扰点
for (int i = 0; i < 200; i++) {
int x = (int) (Math.random() * WIDTH);
int y = (int) (Math.random() * HEIGHT);
g.setColor(getRandomColor());
g.drawOval(x, y, 1, 1);
}
}
/**
* @description: 获取随机颜色
* @param: no
* @return: java.awt.Color
*/
private static Color getRandomColor() {
Random ran = new Random();
return new Color(ran.nextInt(220), ran.nextInt(220), ran.nextInt(220));
}
}
4.token的工具类
package top.remained.util;
import io.jsonwebtoken.*;
import org.springframework.util.StringUtils;
import java.util.Date;
/**
* Project:boot_zhxy
* Date:2022/8/12
* Time:20:57
* Description:TODO
*
* @author lmk
* @version 1.0
*/
public class JwtHelper {
private static long tokenExpiration = 24*60*60*1000;
private static String tokenSignKey = "123456";
//JwtHelper.createToken(admin.getId().longValue(), 1)
// JSON Web Token (JWT)是一种基于 token 的认证方案
//生成token字符串
public static String createToken(Long userId, Integer userType) {
//这里其实就是new一个JwtBuilder,设置jwt的body
String token = Jwts.builder()
// 分组
.setSubject("YYGH-USER")
// 设置有效时间
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
.claim("userId", userId)
// .claim("userName", userName)
.claim("userType", userType)
// 设置签名使用的签名算法和签名使用的秘钥
.signWith(SignatureAlgorithm.HS512, tokenSignKey)
.compressWith(CompressionCodecs.GZIP)
.compact();
return token;
}
//从token字符串获取userid 反解析
public static Long getUserId(String token) {
if(StringUtils.isEmpty(token)) return null;
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
Integer userId = (Integer)claims.get("userId");
return userId.longValue();
}
//从token字符串获取userType
public static Integer getUserType(String token) {
if(StringUtils.isEmpty(token)) return null;
Jws<Claims> claimsJws
= Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
return (Integer)(claims.get("userType"));
}
//从token字符串获取userName
public static String getUserName(String token) {
if(StringUtils.isEmpty(token)) return "";
Jws<Claims> claimsJws
= Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
return (String)claims.get("userName");
}
//判断token是否有效
public static boolean isExpiration(String token){
try {
boolean isExpire = Jwts.parser()
.setSigningKey(tokenSignKey)
.parseClaimsJws(token)
.getBody()
.getExpiration().before(new Date());
//没有过期,有效,返回false
return isExpire;
}catch(Exception e) {
//过期出现异常,返回true
return true;
}
}
/**
* 刷新Token
* @param token
* @return
*/
public String refreshToken(String token) {
String refreshedToken;
try {
final Claims claims = Jwts.parser()
.setSigningKey(tokenSignKey)
.parseClaimsJws(token)
.getBody();
refreshedToken = JwtHelper.createToken(getUserId(token), getUserType(token));
} catch (Exception e) {
refreshedToken = null;
}
return refreshedToken;
}
public static void main(String[] args) {
// String token = JwtHelper.createToken(1L, "lucy");
// System.out.println(token);
// System.out.println(JwtHelper.getUserId(token));
// System.out.println(JwtHelper.getUserName(token));
}
}
二.编写逻辑
1.index页面初始化之后前端发送请求得到验证码
@ApiOperation("获取验证码图片")
@GetMapping("/getVerifiCodeImage")
public void getVerifiCodeImage(HttpServletRequest request, HttpServletResponse response){
// 获取图片
BufferedImage verifiCodeImage = CreateVerifiCodeImage.getVerifiCodeImage();
// 获取图片上的验证码
String verifiCode =new String( CreateVerifiCodeImage.getVerifiCode());
// 将验证码文本放入session域,为下一次验证做准备
HttpSession session = request.getSession();
session.setAttribute("verifiCode",verifiCode);
// 将验证码图片响应给浏览器
try {
ImageIO.write(verifiCodeImage,"JPEG",response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
2.登陆时进行验证码的判断
@PostMapping("/login")
public Result login(
// LoginForm 与用户登录表单信息一一对应 并不是实际的一张表
@ApiParam("登录提交信息的form表单")@RequestBody LoginForm loginForm,
HttpServletRequest request){
HttpSession session = request.getSession();
// 获取上次存在session里面的验证码
String sessionVerifiCode = (String)session.getAttribute("verifiCode");
// 获取用户参数的验证码
String loginVerifiCode = loginForm.getVerifiCode();
// 验证码匹是否输入
if("".equals(sessionVerifiCode) || null == sessionVerifiCode){
return Result.fail().message("验证码失效,请刷新后重试");
}
// 验证码匹配
if (!sessionVerifiCode.equalsIgnoreCase(loginVerifiCode)){
return Result.fail().message("验证码有误,请小心输入后重试");
}
// 从session域中移除现有验证码
session.removeAttribute("verifiCode");
3.登录时用到的java类,和数据库无关
@Data
public class LoginForm {
private String username;
private String password;
private String verifiCode;
private Integer userType;
}
4.验证码判断之后进行用户类型进行判断并进行token生成并放到map中返回给前端
// 准备一个map用户存放响应的数据
// 判断用户类型
Map<String,Object> map=new LinkedHashMap<>();
switch (loginForm.getUserType()){
case 1:
try {
Admin admin=adminService.login(loginForm);
if (null != admin) {
// 用户的类型和用户id转换成一个密文,以token的名称向客户端反馈
map.put("token",JwtHelper.createToken(admin.getId().longValue(), 1));
}else{
throw new RuntimeException("用户名或者密码有误");
}
return Result.ok(map);
} catch (RuntimeException e) {
e.printStackTrace();
return Result.fail().message(e.getMessage());
}
case 2:
try {
Student student =studentService.login(loginForm);
if (null != student) {
// 用户的类型和用户id转换成一个密文,以token的名称向客户端反馈
map.put("token",JwtHelper.createToken(student.getId().longValue(), 2));
}else{
throw new RuntimeException("用户名或者密码有误");
}
return Result.ok(map);
} catch (RuntimeException e) {
e.printStackTrace();
return Result.fail().message(e.getMessage());
}
case 3:
try {
Teacher teahcer =teacherService.login(loginForm);
if (null != teahcer) {
// 用户的类型和用户id转换成一个密文,以token的名称向客户端反馈
map.put("token",JwtHelper.createToken(teahcer.getId().longValue(), 3));
}else{
throw new RuntimeException("用户名或者密码有误");
}
return Result.ok(map);
} catch (RuntimeException e) {
e.printStackTrace();
return Result.fail().message(e.getMessage());
}
}
return Result.fail().message("查无此用户");
}
5.通过token口令获取当前登录的用户信息
@GetMapping("/getInfo")
public Result getInfoByToken(
@ApiParam("token口令")@RequestHeader("token") String token){
// 判断是否失效
boolean expiration = JwtHelper.isExpiration(token);
if (expiration) {
return Result.build(null,ResultCodeEnum.TOKEN_ERROR);
}
//从token中解析出 用户id 和用户的类型
Long userId = JwtHelper.getUserId(token);
Integer userType = JwtHelper.getUserType(token);
6.根据用户类型id查出用户和原来的类型一并保存到Map中返回给前端
类型主要是返回什么页面
Map<String,Object> map =new LinkedHashMap<>();
switch (userType){
case 1:
Admin admin =adminService.getAdminById(userId);
map.put("userType",1);
map.put("user",admin);
break;
case 2:
Student student =studentService.getStudentById(userId);
map.put("userType",2);
map.put("user",student);
break;
case 3:
Teacher teacher= teacherService.getByTeacherById(userId);
map.put("userType",3);
map.put("user",teacher);
break;
}
return Result.ok(map);
}