diff --git a/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/config/WebConfig.java b/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/config/WebConfig.java index 3f29c6b..373bf83 100644 --- a/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/config/WebConfig.java +++ b/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/config/WebConfig.java @@ -3,11 +3,13 @@ package cn.edu.hfut.rmdjzz.projectmanagement.config; import cn.edu.hfut.rmdjzz.projectmanagement.interceptor.CorsInterceptor; import cn.edu.hfut.rmdjzz.projectmanagement.interceptor.TokenInterceptor; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import javax.annotation.Resource; +import java.security.Permission; /** * @author 张韬 @@ -15,17 +17,17 @@ import javax.annotation.Resource; */ @Configuration public class WebConfig implements WebMvcConfigurer { - @Autowired - private CorsInterceptor corsInterceptor; - + @Bean + public CorsInterceptor getCorsInterceptor(){return new CorsInterceptor();} + @Bean + public TokenInterceptor getTokenInterceptor(){return new TokenInterceptor();} @Override public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(corsInterceptor).addPathPatterns("/**"); - registry.addInterceptor(new TokenInterceptor()) + registry.addInterceptor(getCorsInterceptor()).addPathPatterns("/**"); + registry.addInterceptor(getTokenInterceptor()) .addPathPatterns("/**") .excludePathPatterns("/staff/login") - .excludePathPatterns("/hello") - .excludePathPatterns("/staff/hello2"); + .excludePathPatterns("/hello"); } /* @Override diff --git a/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/controller/StaffController.java b/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/controller/StaffController.java index 2f4fb13..8b349a4 100644 --- a/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/controller/StaffController.java +++ b/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/controller/StaffController.java @@ -1,6 +1,7 @@ package cn.edu.hfut.rmdjzz.projectmanagement.controller; import cn.edu.hfut.rmdjzz.projectmanagement.entity.Staff; +import cn.edu.hfut.rmdjzz.projectmanagement.exception.TokenException; import cn.edu.hfut.rmdjzz.projectmanagement.service.impl.StaffServiceImpl; import cn.edu.hfut.rmdjzz.projectmanagement.utils.response.ResponseMap; import lombok.SneakyThrows; @@ -10,6 +11,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.servlet.http.HttpServletRequest; + /** * @author 张韬 * created at 2022/6/28 21:59 @@ -26,8 +29,14 @@ public class StaffController { return staffServiceImpl.login(staff.getStaffUsername(), staff.getStaffPassword()); } - @RequestMapping("/hello2") - public ResponseMap hello2(@RequestBody Staff str) { - return ResponseMap.ofSuccess("adada", str); + @SneakyThrows + @PostMapping("/logout") + public ResponseMap logout(HttpServletRequest request) { + String token= request.getHeader("Token"); + if(staffServiceImpl.logout(token)) + return ResponseMap.ofSuccess("操作成功"); + else{ + throw new TokenException("操作失败"); + } } } diff --git a/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/interceptor/TokenInterceptor.java b/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/interceptor/TokenInterceptor.java index 1be9ba8..266b78d 100644 --- a/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/interceptor/TokenInterceptor.java +++ b/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/interceptor/TokenInterceptor.java @@ -7,6 +7,9 @@ import cn.edu.hfut.rmdjzz.projectmanagement.utils.response.ResponseMap; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; @@ -16,6 +19,8 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.util.Objects; +import java.util.concurrent.TimeUnit; /** * @author 张韬 @@ -24,30 +29,32 @@ import java.io.IOException; //FIXME: objectMapper去掉 @Component public class TokenInterceptor implements HandlerInterceptor { + @Resource + private RedisTemplate redisTemplate; @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws TokenException, IOException { System.out.println(httpServletRequest.getRequestURL()+" "+httpServletRequest.getMethod()); - throw new TokenException("in token"); - /*if (!(object instanceof HandlerMethod)) { - return false; - } String token = httpServletRequest.getHeader("Token"); if (null == token || "".equals(token.trim())) { - ResponseMap res= ResponseMap.of(HttpStatus.UNAUTHORIZED.value(),"缺少Token"); - httpServletResponse.getWriter().print(objectMapper.writeValueAsString(res)); - return false; + throw new TokenException("缺少Token"); } if(!TokenUtils.checkToken(token)){ - ResponseMap res= ResponseMap.of(HttpStatus.UNAUTHORIZED.value(),"无效的Token"); - httpServletResponse.getWriter().print(objectMapper.writeValueAsString(res)); - return false; + throw new TokenException("无效的Token"); } if(TokenUtils.checkTimeOut(token)){ - ResponseMap res= ResponseMap.of(HttpStatus.UNAUTHORIZED.value(),"Token已过期"); - httpServletResponse.getWriter().print(objectMapper.writeValueAsString(res)); - return false; + throw new TokenException("Token已过期"); } - httpServletResponse.setHeader("Token",TokenUtils.autoRequire(token)); - return true;*/ + System.out.println(Objects.requireNonNull(TokenUtils.getStaffId(token))); + System.out.println(token); + if(!token.equals(redisTemplate.opsForValue().get(Objects.requireNonNull(TokenUtils.getStaffId(token))))){ + throw new TokenException("请重新登录"); + } + String newToken=TokenUtils.autoRequire(token); + if(!newToken.equals(token)){ + redisTemplate.opsForValue().set(Objects.requireNonNull(TokenUtils.getStaffId(token)), + token,Objects.requireNonNull(TokenUtils.getDuration(token)), TimeUnit.SECONDS); + } + httpServletResponse.setHeader("Token",newToken); + return true; } } diff --git a/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/service/IStaffService.java b/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/service/IStaffService.java index 03c9360..cad1051 100644 --- a/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/service/IStaffService.java +++ b/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/service/IStaffService.java @@ -2,6 +2,7 @@ package cn.edu.hfut.rmdjzz.projectmanagement.service; import cn.edu.hfut.rmdjzz.projectmanagement.entity.Staff; import cn.edu.hfut.rmdjzz.projectmanagement.exception.BadRequestException; +import cn.edu.hfut.rmdjzz.projectmanagement.exception.TokenException; import cn.edu.hfut.rmdjzz.projectmanagement.utils.response.ResponseMap; import com.baomidou.mybatisplus.extension.service.IService; @@ -10,5 +11,6 @@ import com.baomidou.mybatisplus.extension.service.IService; * @since 2022/6/28 17:28 */ public interface IStaffService extends IService { - ResponseMap login(String username, String password) throws BadRequestException; + ResponseMap login(String username, String password) throws BadRequestException, TokenException; + Boolean logout(String token) throws TokenException; } diff --git a/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/service/impl/StaffServiceImpl.java b/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/service/impl/StaffServiceImpl.java index af2fdb4..57e6d4d 100644 --- a/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/service/impl/StaffServiceImpl.java +++ b/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/service/impl/StaffServiceImpl.java @@ -2,6 +2,7 @@ package cn.edu.hfut.rmdjzz.projectmanagement.service.impl; import cn.edu.hfut.rmdjzz.projectmanagement.entity.Staff; import cn.edu.hfut.rmdjzz.projectmanagement.exception.BadRequestException; +import cn.edu.hfut.rmdjzz.projectmanagement.exception.TokenException; import cn.edu.hfut.rmdjzz.projectmanagement.mapper.StaffMapper; import cn.edu.hfut.rmdjzz.projectmanagement.service.IStaffService; import cn.edu.hfut.rmdjzz.projectmanagement.utils.TokenUtils; @@ -9,35 +10,62 @@ 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.fasterxml.jackson.core.JsonProcessingException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import org.springframework.util.DigestUtils; +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + /** * @author 佘语殊 * @since 2022/6/28 17:29 */ @Service public class StaffServiceImpl extends ServiceImpl implements IStaffService { + private static final Long tokenDuration=5*60*60L; + @Resource + private RedisTemplate redisTemplate; @Override - public ResponseMap login(String username, String password) throws BadRequestException { - if (username == null || username.trim().length() == 0) + public ResponseMap login(String staffUsername, String password) throws BadRequestException, TokenException { + if (staffUsername == null || staffUsername.trim().length() == 0) throw new BadRequestException("用户名为空"); - else if (!username.equals(username.replaceAll("[^a-zA-Z0-9]", ""))) + else if (!staffUsername.equals(staffUsername.replaceAll("[^a-zA-Z0-9]", ""))) throw new BadRequestException("用户名格式错误"); else if (password == null || password.trim().length() != 32) throw new BadRequestException("密码格式错误"); - Staff staff = getOne(Wrappers.lambdaQuery().eq(Staff::getStaffUsername, username)); + Staff staff = getOne(Wrappers.lambdaQuery().eq(Staff::getStaffUsername, staffUsername)); if (staff == null) throw new BadRequestException("用户不存在"); password = DigestUtils.md5DigestAsHex((password + staff.getStaffSalt()).getBytes()); if (!staff.getStaffPassword().equals(password)) throw new BadRequestException("密码错误"); + String token=TokenUtils.getToken(staff.getStaffUsername(), staff.getStaffId(),tokenDuration); + redisTemplate.opsForValue().set(Objects.requireNonNull(TokenUtils.getStaffId(token)), + token,Objects.requireNonNull(TokenUtils.getDuration(token)), TimeUnit.SECONDS); return ResponseMap.ofSuccess("ok") - .put("Token", TokenUtils.getToken(staff.getStaffUsername(), staff.getStaffId())) - .put("staffUsername", username) + .put("Token",token) + .put("staffUsername", staffUsername) .put("staffFullname", staff.getStaffFullname()) .put("staffId", staff.getStaffId()); } + @Override + public Boolean logout(String token) throws TokenException { + Integer staffId=TokenUtils.getStaffId(token); + if(staffId==null) + return false; + String remoteToken= redisTemplate.opsForValue().get(staffId); + if(!token.equals(remoteToken)) + return false; + redisTemplate.delete(staffId); + return true; + + } } diff --git a/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/utils/TokenUtils.java b/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/utils/TokenUtils.java index 3de8e7c..2719805 100644 --- a/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/utils/TokenUtils.java +++ b/src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/utils/TokenUtils.java @@ -6,25 +6,31 @@ import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTVerificationException; import com.auth0.jwt.interfaces.DecodedJWT; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; +import javax.annotation.Resource; import java.util.Date; +import java.util.concurrent.TimeUnit; /** * @author 张韬 * created at 2022/6/28 18:20 */ //TODO: 演示的时候把expireTime改短点儿 + +@Component public final class TokenUtils { public final static String pvKey = "SignedByRMDJZZ"; - - public static String getToken(String username, Integer staffId) { + public static String getToken(String staffUsername, Integer staffId,Long duration) { return JWT.create() - .withClaim("username", username) + .withClaim("staffUsername", staffUsername) .withClaim("staffId", staffId) + .withClaim("duration",duration) .withIssuedAt(new Date()) - .withExpiresAt(new Date(System.currentTimeMillis() + 5 * 60 * 60 * 1000)) + .withExpiresAt(new Date(System.currentTimeMillis() + duration*1000L)) .sign(Algorithm.HMAC256(pvKey)); - } public static boolean checkToken(String token) throws TokenException { @@ -33,7 +39,7 @@ public final class TokenUtils { verifier.verify(token); return true; } catch (JWTVerificationException e) { - throw new TokenException("非法的Token"); + throw new TokenException("无效的Token"); } } @@ -46,7 +52,7 @@ public final class TokenUtils { public static String getUsername(String token) throws TokenException { if (!checkToken(token)) return null; - return JWT.decode(token).getClaim("username").asString(); + return JWT.decode(token).getClaim("staffUsername").asString(); } public static Integer getStaffId(String token) throws TokenException { @@ -54,9 +60,13 @@ public final class TokenUtils { return null; return JWT.decode(token).getClaim("staffId").asInt(); } - + public static Long getDuration(String token) throws TokenException { + if (!checkToken(token)) + return null; + return JWT.decode(token).getClaim("duration").asLong(); + } public static String refreshToken(String token) throws TokenException { - return getToken(getUsername(token), getStaffId(token)); + return getToken(getUsername(token), getStaffId(token),getDuration(token)); } public static String autoRequire(String token) throws TokenException {