初步完成了Redis情况下的登录、登出和Token验证,*此处有重大注意事项:拦截器请使用Bean注入,否则redis无法注入!!!
parent
2c9a880c23
commit
132abb270a
|
@ -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.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.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
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;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.security.Permission;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 张韬
|
* @author 张韬
|
||||||
|
@ -15,17 +17,17 @@ import javax.annotation.Resource;
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
public class WebConfig implements WebMvcConfigurer {
|
public class WebConfig implements WebMvcConfigurer {
|
||||||
@Autowired
|
@Bean
|
||||||
private CorsInterceptor corsInterceptor;
|
public CorsInterceptor getCorsInterceptor(){return new CorsInterceptor();}
|
||||||
|
@Bean
|
||||||
|
public TokenInterceptor getTokenInterceptor(){return new TokenInterceptor();}
|
||||||
@Override
|
@Override
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
registry.addInterceptor(corsInterceptor).addPathPatterns("/**");
|
registry.addInterceptor(getCorsInterceptor()).addPathPatterns("/**");
|
||||||
registry.addInterceptor(new TokenInterceptor())
|
registry.addInterceptor(getTokenInterceptor())
|
||||||
.addPathPatterns("/**")
|
.addPathPatterns("/**")
|
||||||
.excludePathPatterns("/staff/login")
|
.excludePathPatterns("/staff/login")
|
||||||
.excludePathPatterns("/hello")
|
.excludePathPatterns("/hello");
|
||||||
.excludePathPatterns("/staff/hello2");
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package cn.edu.hfut.rmdjzz.projectmanagement.controller;
|
package cn.edu.hfut.rmdjzz.projectmanagement.controller;
|
||||||
|
|
||||||
import cn.edu.hfut.rmdjzz.projectmanagement.entity.Staff;
|
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.service.impl.StaffServiceImpl;
|
||||||
import cn.edu.hfut.rmdjzz.projectmanagement.utils.response.ResponseMap;
|
import cn.edu.hfut.rmdjzz.projectmanagement.utils.response.ResponseMap;
|
||||||
import lombok.SneakyThrows;
|
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.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 张韬
|
* @author 张韬
|
||||||
* created at 2022/6/28 21:59
|
* created at 2022/6/28 21:59
|
||||||
|
@ -26,8 +29,14 @@ public class StaffController {
|
||||||
return staffServiceImpl.login(staff.getStaffUsername(), staff.getStaffPassword());
|
return staffServiceImpl.login(staff.getStaffUsername(), staff.getStaffPassword());
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping("/hello2")
|
@SneakyThrows
|
||||||
public ResponseMap hello2(@RequestBody Staff str) {
|
@PostMapping("/logout")
|
||||||
return ResponseMap.ofSuccess("adada", str);
|
public ResponseMap logout(HttpServletRequest request) {
|
||||||
|
String token= request.getHeader("Token");
|
||||||
|
if(staffServiceImpl.logout(token))
|
||||||
|
return ResponseMap.ofSuccess("操作成功");
|
||||||
|
else{
|
||||||
|
throw new TokenException("操作失败");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,9 @@ import cn.edu.hfut.rmdjzz.projectmanagement.utils.response.ResponseMap;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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.http.HttpStatus;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.method.HandlerMethod;
|
import org.springframework.web.method.HandlerMethod;
|
||||||
|
@ -16,6 +19,8 @@ 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;
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 张韬
|
* @author 张韬
|
||||||
|
@ -24,30 +29,32 @@ import java.io.IOException;
|
||||||
//FIXME: objectMapper去掉
|
//FIXME: objectMapper去掉
|
||||||
@Component
|
@Component
|
||||||
public class TokenInterceptor implements HandlerInterceptor {
|
public class TokenInterceptor implements HandlerInterceptor {
|
||||||
|
@Resource
|
||||||
|
private RedisTemplate<Integer,String> redisTemplate;
|
||||||
@Override
|
@Override
|
||||||
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws TokenException, IOException {
|
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());
|
||||||
throw new TokenException("in token");
|
|
||||||
/*if (!(object instanceof HandlerMethod)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String token = httpServletRequest.getHeader("Token");
|
String token = httpServletRequest.getHeader("Token");
|
||||||
if (null == token || "".equals(token.trim())) {
|
if (null == token || "".equals(token.trim())) {
|
||||||
ResponseMap res= ResponseMap.of(HttpStatus.UNAUTHORIZED.value(),"缺少Token");
|
throw new TokenException("缺少Token");
|
||||||
httpServletResponse.getWriter().print(objectMapper.writeValueAsString(res));
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if(!TokenUtils.checkToken(token)){
|
if(!TokenUtils.checkToken(token)){
|
||||||
ResponseMap res= ResponseMap.of(HttpStatus.UNAUTHORIZED.value(),"无效的Token");
|
throw new TokenException("无效的Token");
|
||||||
httpServletResponse.getWriter().print(objectMapper.writeValueAsString(res));
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if(TokenUtils.checkTimeOut(token)){
|
if(TokenUtils.checkTimeOut(token)){
|
||||||
ResponseMap res= ResponseMap.of(HttpStatus.UNAUTHORIZED.value(),"Token已过期");
|
throw new TokenException("Token已过期");
|
||||||
httpServletResponse.getWriter().print(objectMapper.writeValueAsString(res));
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
httpServletResponse.setHeader("Token",TokenUtils.autoRequire(token));
|
System.out.println(Objects.requireNonNull(TokenUtils.getStaffId(token)));
|
||||||
return true;*/
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.entity.Staff;
|
||||||
import cn.edu.hfut.rmdjzz.projectmanagement.exception.BadRequestException;
|
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 cn.edu.hfut.rmdjzz.projectmanagement.utils.response.ResponseMap;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
@ -10,5 +11,6 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
* @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 BadRequestException;
|
ResponseMap login(String username, String password) throws BadRequestException, TokenException;
|
||||||
|
Boolean logout(String token) throws TokenException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.entity.Staff;
|
||||||
import cn.edu.hfut.rmdjzz.projectmanagement.exception.BadRequestException;
|
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.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.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.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.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.stereotype.Service;
|
||||||
import org.springframework.util.DigestUtils;
|
import org.springframework.util.DigestUtils;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 佘语殊
|
* @author 佘语殊
|
||||||
* @since 2022/6/28 17:29
|
* @since 2022/6/28 17:29
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements IStaffService {
|
public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements IStaffService {
|
||||||
|
private static final Long tokenDuration=5*60*60L;
|
||||||
|
@Resource
|
||||||
|
private RedisTemplate<Integer,String> redisTemplate;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResponseMap login(String username, String password) throws BadRequestException {
|
public ResponseMap login(String staffUsername, String password) throws BadRequestException, TokenException {
|
||||||
if (username == null || username.trim().length() == 0)
|
if (staffUsername == null || staffUsername.trim().length() == 0)
|
||||||
throw new BadRequestException("用户名为空");
|
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("用户名格式错误");
|
throw new BadRequestException("用户名格式错误");
|
||||||
else if (password == null || password.trim().length() != 32)
|
else if (password == null || password.trim().length() != 32)
|
||||||
throw new BadRequestException("密码格式错误");
|
throw new BadRequestException("密码格式错误");
|
||||||
|
|
||||||
Staff staff = getOne(Wrappers.<Staff>lambdaQuery().eq(Staff::getStaffUsername, username));
|
Staff staff = getOne(Wrappers.<Staff>lambdaQuery().eq(Staff::getStaffUsername, staffUsername));
|
||||||
if (staff == null)
|
if (staff == null)
|
||||||
throw new BadRequestException("用户不存在");
|
throw new BadRequestException("用户不存在");
|
||||||
password = DigestUtils.md5DigestAsHex((password + staff.getStaffSalt()).getBytes());
|
password = DigestUtils.md5DigestAsHex((password + staff.getStaffSalt()).getBytes());
|
||||||
if (!staff.getStaffPassword().equals(password))
|
if (!staff.getStaffPassword().equals(password))
|
||||||
throw new BadRequestException("密码错误");
|
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")
|
return ResponseMap.ofSuccess("ok")
|
||||||
.put("Token", TokenUtils.getToken(staff.getStaffUsername(), staff.getStaffId()))
|
.put("Token",token)
|
||||||
.put("staffUsername", username)
|
.put("staffUsername", staffUsername)
|
||||||
.put("staffFullname", staff.getStaffFullname())
|
.put("staffFullname", staff.getStaffFullname())
|
||||||
.put("staffId", staff.getStaffId());
|
.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;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,25 +6,31 @@ import com.auth0.jwt.JWTVerifier;
|
||||||
import com.auth0.jwt.algorithms.Algorithm;
|
import com.auth0.jwt.algorithms.Algorithm;
|
||||||
import com.auth0.jwt.exceptions.JWTVerificationException;
|
import com.auth0.jwt.exceptions.JWTVerificationException;
|
||||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
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.Date;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 张韬
|
* @author 张韬
|
||||||
* created at 2022/6/28 18:20
|
* created at 2022/6/28 18:20
|
||||||
*/
|
*/
|
||||||
//TODO: 演示的时候把expireTime改短点儿
|
//TODO: 演示的时候把expireTime改短点儿
|
||||||
|
|
||||||
|
@Component
|
||||||
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 staffUsername, Integer staffId,Long duration) {
|
||||||
public static String getToken(String username, Integer staffId) {
|
|
||||||
return JWT.create()
|
return JWT.create()
|
||||||
.withClaim("username", username)
|
.withClaim("staffUsername", staffUsername)
|
||||||
.withClaim("staffId", staffId)
|
.withClaim("staffId", staffId)
|
||||||
|
.withClaim("duration",duration)
|
||||||
.withIssuedAt(new Date())
|
.withIssuedAt(new Date())
|
||||||
.withExpiresAt(new Date(System.currentTimeMillis() + 5 * 60 * 60 * 1000))
|
.withExpiresAt(new Date(System.currentTimeMillis() + duration*1000L))
|
||||||
.sign(Algorithm.HMAC256(pvKey));
|
.sign(Algorithm.HMAC256(pvKey));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean checkToken(String token) throws TokenException {
|
public static boolean checkToken(String token) throws TokenException {
|
||||||
|
@ -33,7 +39,7 @@ public final class TokenUtils {
|
||||||
verifier.verify(token);
|
verifier.verify(token);
|
||||||
return true;
|
return true;
|
||||||
} catch (JWTVerificationException e) {
|
} 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 {
|
public static String getUsername(String token) throws TokenException {
|
||||||
if (!checkToken(token))
|
if (!checkToken(token))
|
||||||
return null;
|
return null;
|
||||||
return JWT.decode(token).getClaim("username").asString();
|
return JWT.decode(token).getClaim("staffUsername").asString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Integer getStaffId(String token) throws TokenException {
|
public static Integer getStaffId(String token) throws TokenException {
|
||||||
|
@ -54,9 +60,13 @@ public final class TokenUtils {
|
||||||
return null;
|
return null;
|
||||||
return JWT.decode(token).getClaim("staffId").asInt();
|
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 {
|
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 {
|
public static String autoRequire(String token) throws TokenException {
|
||||||
|
|
Loading…
Reference in New Issue