完成了没有Redis情况下的登录和Token验证

master
张韬 2022-06-28 23:40:30 +08:00
parent d4ef6ea2cf
commit 1397496bc3
11 changed files with 125 additions and 55 deletions

View File

@ -2,6 +2,7 @@ package cn.edu.hfut.rmdjzz.projectmanagement.config;
import cn.edu.hfut.rmdjzz.projectmanagement.interceptor.CorsInterceptor; import cn.edu.hfut.rmdjzz.projectmanagement.interceptor.CorsInterceptor;
import cn.edu.hfut.rmdjzz.projectmanagement.interceptor.TokenInterceptor; import cn.edu.hfut.rmdjzz.projectmanagement.interceptor.TokenInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@ -14,7 +15,7 @@ import javax.annotation.Resource;
*/ */
@Configuration @Configuration
public class WebConfig implements WebMvcConfigurer { public class WebConfig implements WebMvcConfigurer {
@Resource @Autowired
private CorsInterceptor corsInterceptor; private CorsInterceptor corsInterceptor;
@Override @Override

View File

@ -0,0 +1,28 @@
package cn.edu.hfut.rmdjzz.projectmanagement.controller;
import cn.edu.hfut.rmdjzz.projectmanagement.entity.Staff;
import cn.edu.hfut.rmdjzz.projectmanagement.exception.LoginException;
import cn.edu.hfut.rmdjzz.projectmanagement.service.impl.StaffServiceImpl;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.response.ResponseMap;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author
* created at 2022/6/28 21:59
*/
@RestController
@RequestMapping("/api")
public class StaffController {
@Autowired
private StaffServiceImpl staffServiceImpl;
@PostMapping("/login")
public ResponseMap login(@RequestBody Staff staff) throws LoginException, JsonProcessingException {
return staffServiceImpl.login(staff.getStaffUsername(), staff.getStaffPassword());
}
}

View File

@ -1,27 +0,0 @@
package cn.edu.hfut.rmdjzz.projectmanagement.entity;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* @author
* created at 2022/6/28 18:32
*/
@Data
public class Response implements Serializable {
private int code;
private String msg;
Map<String,Object> data = new HashMap<>();
public void put(String key,Object value){
data.put(key,value);
}
public String JsonString() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(this);
}
}

View File

@ -16,4 +16,5 @@ public class Staff {
private String staffPassword; private String staffPassword;
private String staffFullname; private String staffFullname;
private String staffGender; private String staffGender;
private String staffSalt;
} }

View File

@ -0,0 +1,9 @@
package cn.edu.hfut.rmdjzz.projectmanagement.exception;
/**
* @author
* created at 2022/6/28 21:24
*/
public class LoginException extends Exception{
public LoginException(String message){super(message);}
}

View File

@ -0,0 +1,9 @@
package cn.edu.hfut.rmdjzz.projectmanagement.exception;
/**
* @author
* created at 2022/6/28 23:34
*/
public class TokenException extends Exception{
public TokenException(String message){super(message);}
}

View File

@ -1,14 +1,20 @@
package cn.edu.hfut.rmdjzz.projectmanagement.interceptor; package cn.edu.hfut.rmdjzz.projectmanagement.interceptor;
import cn.edu.hfut.rmdjzz.projectmanagement.entity.Response;
import cn.edu.hfut.rmdjzz.projectmanagement.exception.TokenException;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.TokenUtils; import cn.edu.hfut.rmdjzz.projectmanagement.utils.TokenUtils;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.response.ResponseMap;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/** /**
* @author * @author
@ -16,31 +22,31 @@ import javax.servlet.http.HttpServletResponse;
*/ */
@Component @Component
public class TokenInterceptor implements HandlerInterceptor { public class TokenInterceptor implements HandlerInterceptor {
@Resource
private ObjectMapper objectMapper;
@Override @Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception { public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws TokenException, IOException {
System.out.println(httpServletRequest.getRequestURL()+" "+httpServletRequest.getMethod()); System.out.println(httpServletRequest.getRequestURL()+" "+httpServletRequest.getMethod());
if (!(object instanceof HandlerMethod)) { if (!(object instanceof HandlerMethod)) {
return false; return false;
} }
String token = httpServletRequest.getHeader("token"); String token = httpServletRequest.getHeader("Token");
if (null == token || "".equals(token.trim())) { if (null == token || "".equals(token.trim())) {
Response res=new Response(); ResponseMap res= ResponseMap.of(HttpStatus.UNAUTHORIZED.value(),"缺少Token");
res.setMsg("缺少Token"); httpServletResponse.getWriter().print(objectMapper.writeValueAsString(res));
res.setCode(HttpStatus.UNAUTHORIZED.value());
httpServletResponse.getWriter().print(res.JsonString());
return false; return false;
} }
if(token.charAt(0)=='"'||token.charAt(0)=='\'')
token=token.substring(1,token.length()-1);
System.out.println(token);
if(!TokenUtils.checkToken(token)){ if(!TokenUtils.checkToken(token)){
Response res=new Response(); ResponseMap res= ResponseMap.of(HttpStatus.UNAUTHORIZED.value(),"无效的Token");
res.setMsg("无效的Token"); httpServletResponse.getWriter().print(objectMapper.writeValueAsString(res));
res.setCode(HttpStatus.UNAUTHORIZED.value());
httpServletResponse.getWriter().print(res.JsonString());
return false; return false;
} }
httpServletRequest.setAttribute("token", TokenUtils.autoRequire(token)); if(TokenUtils.checkTimeOut(token)){
ResponseMap res= ResponseMap.of(HttpStatus.UNAUTHORIZED.value(),"Token已过期");
httpServletResponse.getWriter().print(objectMapper.writeValueAsString(res));
return false;
}
httpServletResponse.setHeader("Token",TokenUtils.autoRequire(token));
return true; return true;
} }
} }

View File

@ -1,11 +1,15 @@
package cn.edu.hfut.rmdjzz.projectmanagement.service; package cn.edu.hfut.rmdjzz.projectmanagement.service;
import cn.edu.hfut.rmdjzz.projectmanagement.entity.Staff; import cn.edu.hfut.rmdjzz.projectmanagement.entity.Staff;
import cn.edu.hfut.rmdjzz.projectmanagement.exception.LoginException;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.response.ResponseMap;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.fasterxml.jackson.core.JsonProcessingException;
/** /**
* @author * @author
* @since 2022/6/28 17:28 * @since 2022/6/28 17:28
*/ */
public interface IStaffService extends IService<Staff> { public interface IStaffService extends IService<Staff> {
ResponseMap login(String username, String password) throws LoginException, JsonProcessingException;
} }

View File

@ -1,10 +1,20 @@
package cn.edu.hfut.rmdjzz.projectmanagement.service.impl; package cn.edu.hfut.rmdjzz.projectmanagement.service.impl;
import cn.edu.hfut.rmdjzz.projectmanagement.entity.Staff; import cn.edu.hfut.rmdjzz.projectmanagement.entity.Staff;
import cn.edu.hfut.rmdjzz.projectmanagement.exception.LoginException;
import cn.edu.hfut.rmdjzz.projectmanagement.mapper.StaffMapper; import cn.edu.hfut.rmdjzz.projectmanagement.mapper.StaffMapper;
import cn.edu.hfut.rmdjzz.projectmanagement.service.IStaffService; import cn.edu.hfut.rmdjzz.projectmanagement.service.IStaffService;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.TokenUtils;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.response.ResponseMap;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import javax.annotation.Resource;
/** /**
* @author * @author
@ -12,4 +22,25 @@ import org.springframework.stereotype.Service;
*/ */
@Service @Service
public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements IStaffService { public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements IStaffService {
@Override
public ResponseMap login(String username, String password) throws LoginException, JsonProcessingException {
if(username==null||username.trim().length()==0)
throw new LoginException("用户名为空");
else if(!username.equals(username.replaceAll("[^a-zA-Z0-9]", "")))
throw new LoginException("用户名格式错误");
else if(password==null||password.trim().length()!=32)
throw new LoginException("密码格式错误");
Staff staff = getOne(Wrappers.<Staff>lambdaQuery().eq(Staff::getStaffUsername,username));
if(staff==null)
throw new LoginException("用户不存在");
password= DigestUtils.md5DigestAsHex((password+staff.getStaffSalt()).getBytes());
if(!staff.getStaffPassword().equals(password))
throw new LoginException("密码错误");
ResponseMap res=ResponseMap.ofSuccess("ok").put("username",username);
res.put("Token",TokenUtils.getToken(staff.getStaffUsername(),staff.getStaffId()));
res.put("staffFullname",staff.getStaffFullname());
res.put("staffId",staff.getStaffId());
return res;
}
} }

View File

@ -1,5 +1,6 @@
package cn.edu.hfut.rmdjzz.projectmanagement.utils; package cn.edu.hfut.rmdjzz.projectmanagement.utils;
import cn.edu.hfut.rmdjzz.projectmanagement.exception.TokenException;
import com.auth0.jwt.JWT; import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.algorithms.Algorithm;
@ -12,40 +13,46 @@ import java.util.Date;
* @author * @author
* created at 2022/6/28 18:20 * created at 2022/6/28 18:20
*/ */
//TODO: 演示的时候把expireTime改短点儿
public final class TokenUtils { public final class TokenUtils {
public final static String pvKey="SignedByRMDJZZ"; public final static String pvKey="SignedByRMDJZZ";
public static String getToken(String username){ public static String getToken(String username,Integer staffId){
return JWT.create() return JWT.create()
.withClaim("username", username) .withClaim("username", username)
.withClaim("staffId", staffId)
.withIssuedAt(new Date()) .withIssuedAt(new Date())
.withExpiresAt(new Date(System.currentTimeMillis() + 5*60*60*1000)) .withExpiresAt(new Date(System.currentTimeMillis() + 5*60*60*1000))
.sign(Algorithm.HMAC256(pvKey)); .sign(Algorithm.HMAC256(pvKey));
} }
public static boolean checkToken(String token) { public static boolean checkToken(String token) throws TokenException {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(pvKey)).build(); JWTVerifier verifier = JWT.require(Algorithm.HMAC256(pvKey)).build();
try { try {
verifier.verify(token); verifier.verify(token);
return true; return true;
} catch (JWTVerificationException e) { } catch (JWTVerificationException e) {
e.printStackTrace(); throw new TokenException("非法的Token");
return false;
} }
} }
public static boolean checkTimeOut(String token){ public static boolean checkTimeOut(String token) throws TokenException {
if(!checkToken(token)) if(!checkToken(token))
return true; return true;
return JWT.decode(token).getClaim("exp").asLong()<(System.currentTimeMillis()/1000); return JWT.decode(token).getClaim("exp").asLong()<(System.currentTimeMillis()/1000);
} }
public static String getUsername(String token){ public static String getUsername(String token) throws TokenException {
if(!checkToken(token)) if(!checkToken(token))
return ""; return null;
return JWT.decode(token).getClaim("username").asString(); return JWT.decode(token).getClaim("username").asString();
} }
public static String refreshToken(String token) { public static Integer getStaffId(String token) throws TokenException {
return getToken(getUsername(token)); if(!checkToken(token))
return null;
return JWT.decode(token).getClaim("staffId").asInt();
} }
public static String autoRequire(String token) { public static String refreshToken(String token) throws TokenException {
return getToken(getUsername(token),getStaffId(token));
}
public static String autoRequire(String token) throws TokenException {
boolean check = checkToken(token); boolean check = checkToken(token);
if (check) { if (check) {
DecodedJWT jwt = JWT.decode(token); DecodedJWT jwt = JWT.decode(token);

View File

@ -2,12 +2,14 @@ package cn.edu.hfut.rmdjzz.projectmanagement.utils.response;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.BeanUtils; import cn.edu.hfut.rmdjzz.projectmanagement.utils.BeanUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import org.springframework.core.serializer.support.SerializationFailedException; import org.springframework.core.serializer.support.SerializationFailedException;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import javax.annotation.Resource;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -18,13 +20,12 @@ import java.util.Map;
* @author * @author
* @since 2022/6/28 21:29 * @since 2022/6/28 21:29
*/ */
@AllArgsConstructor(access = AccessLevel.PRIVATE) @AllArgsConstructor(access = AccessLevel.PUBLIC)
@Data @Data
public class ResponseMap { public class ResponseMap {
private Integer code; private Integer code;
private String msg; private String msg;
private Map<String, Object> data; private Map<String, Object> data;
/** /**
* *
* *