diff --git a/.gitignore b/.gitignore index feff169..453b430 100755 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,4 @@ build/ ### 自定义 ### *.pdf /src/main/resources/application-dev.yml +/src/main/resources/application-test.yml diff --git a/pom.xml b/pom.xml index 7c6fe34..55a3758 100755 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,7 @@ JSL_OrganizeInternalOA 1.8 + true diff --git a/src/main/java/com/jsl/oa/aspect/UserControllerAspect.java b/src/main/java/com/jsl/oa/aspect/AuthControllerAspect.java similarity index 66% rename from src/main/java/com/jsl/oa/aspect/UserControllerAspect.java rename to src/main/java/com/jsl/oa/aspect/AuthControllerAspect.java index c40cbae..23c2e33 100755 --- a/src/main/java/com/jsl/oa/aspect/UserControllerAspect.java +++ b/src/main/java/com/jsl/oa/aspect/AuthControllerAspect.java @@ -1,7 +1,10 @@ package com.jsl.oa.aspect; +import com.jsl.oa.common.constant.BusinessConstants; import com.jsl.oa.utils.ErrorCode; import com.jsl.oa.utils.ResultUtil; +import com.jsl.oa.utils.redis.TokenRedisUtil; +import lombok.RequiredArgsConstructor; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @@ -18,23 +21,25 @@ import java.util.Objects; *
* 用于用户控制器的切面 * - * @since v1.0.0 - * @version v1.0.0 * @author 筱锋xiao_lfeng + * @version v1.0.0 + * @since v1.0.0 */ @Aspect @Component -public class UserControllerAspect { +@RequiredArgsConstructor +public class AuthControllerAspect { + private final TokenRedisUtil tokenRedisUtil; /** *

用户控制器切面

*
* 用于用户控制器的切面 * - * @since v1.0.0 * @param pjp ProceedingJoinPoint对象 * @return {@link Object} * @throws Throwable 异常 + * @since v1.0.0 */ @Around("execution(* com.jsl.oa.controllers.AuthController.*(..))") public Object controllerAround(ProceedingJoinPoint pjp) throws Throwable { @@ -51,14 +56,33 @@ public class UserControllerAspect { } + @Around("execution(* com.jsl.oa.controllers.AuthController.authLogout(..)) || execution(* com.jsl.oa.controllers.AuthController.authChangePassword(..))") + public Object tokenControllerAround(ProceedingJoinPoint pjp) throws Throwable { + // 获取 HttpServletRequest 对象 + HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest(); + + // 检查 Token 是否有效 + String token = request.getHeader("Authorization"); + if (token != null && !token.isEmpty()) { + // 获取 Redis 检查 Token 是否存在 + String finalToken = token.replace("Bearer ", ""); + for (String it : tokenRedisUtil.getList(BusinessConstants.BUSINESS_LOGIN)) { + if (it.equals(finalToken)) { + return pjp.proceed(); + } + } + } + return ResultUtil.error(ErrorCode.TOKEN_NOT_EXIST); + } + /** *

时间戳检查

*
* 用于检查时间戳是否合法,合法时间范围正负5秒 * - * @since v1.0.0 * @param request HttpServletRequest对象 * @return {@link Boolean} + * @since v1.0.0 */ public Boolean checkTimestamp(@NotNull HttpServletRequest request) { // 获取请求头中的时间戳 diff --git a/src/main/java/com/jsl/oa/common/constant/BusinessConstants.java b/src/main/java/com/jsl/oa/common/constant/BusinessConstants.java index b824ad0..25cfd8b 100644 --- a/src/main/java/com/jsl/oa/common/constant/BusinessConstants.java +++ b/src/main/java/com/jsl/oa/common/constant/BusinessConstants.java @@ -7,7 +7,8 @@ import lombok.Getter; */ @Getter public enum BusinessConstants { - BUSINESS_LOGIN("login:", "登陆实现"); + BUSINESS_LOGIN("login:", "登陆实现"), + NONE("", "null"); private final String value; private final String description; diff --git a/src/main/java/com/jsl/oa/common/constant/RedisConstant.java b/src/main/java/com/jsl/oa/common/constant/RedisConstant.java index 9551711..6617ef3 100755 --- a/src/main/java/com/jsl/oa/common/constant/RedisConstant.java +++ b/src/main/java/com/jsl/oa/common/constant/RedisConstant.java @@ -17,9 +17,11 @@ public class RedisConstant { * 类型分类 */ public static final String TYPE_EMAIL = "mail:"; // 邮件相关 + public static final String TYPE_AUTH = "auth:"; // 登陆相关 /* * 表分类 */ public static final String TABLE_EMAIL = "code:"; // 邮箱验证码 + public static final String TABLE_TOKEN = "token:"; // 令牌相关 } diff --git a/src/main/java/com/jsl/oa/config/JwtFilter.java b/src/main/java/com/jsl/oa/config/JwtFilter.java index 5589cce..2270844 100755 --- a/src/main/java/com/jsl/oa/config/JwtFilter.java +++ b/src/main/java/com/jsl/oa/config/JwtFilter.java @@ -41,7 +41,6 @@ public class JwtFilter extends BasicHttpAuthenticationFilter { } else { // 解析Bearer后面的令牌 token = token.replace("Bearer ", ""); - System.out.println(token); return JwtUtil.verify(token); } } diff --git a/src/main/java/com/jsl/oa/config/redis/RedisOperating.java b/src/main/java/com/jsl/oa/config/redis/RedisOperating.java index d0bb78a..585a29b 100644 --- a/src/main/java/com/jsl/oa/config/redis/RedisOperating.java +++ b/src/main/java/com/jsl/oa/config/redis/RedisOperating.java @@ -5,6 +5,8 @@ import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; +import java.util.List; +import java.util.Set; import java.util.concurrent.TimeUnit; @RequiredArgsConstructor @@ -56,4 +58,23 @@ public abstract class RedisOperating { redisTemplate.opsForValue().set(key, value); redisTemplate.expire(key, time, TimeUnit.SECONDS); } + + /** + *

基础从Redis获取List

+ *
+ * 基础方法,用于从Redis获取List
+ * + * @param pattern 正则表达式 + * @return 返回List + */ + public List getList(String pattern) { + // 获取全部匹配的key + Set keys = stringRedisTemplate.keys(pattern); + // 获取全部匹配的value + if (keys != null) { + return redisTemplate.opsForValue().multiGet(keys); + } else { + return null; + } + } } \ No newline at end of file diff --git a/src/main/java/com/jsl/oa/controllers/AuthController.java b/src/main/java/com/jsl/oa/controllers/AuthController.java index 3c2eb0d..c705950 100755 --- a/src/main/java/com/jsl/oa/controllers/AuthController.java +++ b/src/main/java/com/jsl/oa/controllers/AuthController.java @@ -1,5 +1,6 @@ package com.jsl.oa.controllers; +import com.jsl.oa.model.voData.UserChangePasswordVO; import com.jsl.oa.model.voData.UserLoginVO; import com.jsl.oa.model.voData.UserRegisterVO; import com.jsl.oa.services.AuthService; @@ -13,7 +14,7 @@ import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import java.text.ParseException; +import javax.servlet.http.HttpServletRequest; import java.util.regex.Pattern; /** @@ -46,7 +47,7 @@ public class AuthController { * @since v1.0.0 */ @PostMapping("/auth/register") - public BaseResponse authRegister(@RequestBody @Validated UserRegisterVO userRegisterVO, @NotNull BindingResult bindingResult) throws ParseException { + public BaseResponse authRegister(@RequestBody @Validated UserRegisterVO userRegisterVO, @NotNull BindingResult bindingResult) { // 判断是否有参数错误 if (bindingResult.hasErrors()) { return ResultUtil.error(ErrorCode.REQUEST_BODY_ERROR, Processing.getValidatedErrorList(bindingResult)); @@ -98,10 +99,16 @@ public class AuthController { } @GetMapping("/auth/login/email") - public BaseResponse authLoginByEmail(@RequestParam String email, @RequestParam Integer code) { - if (email != null && code != null) { + public BaseResponse authLoginByEmail(@RequestParam String email, @RequestParam String code) { + if (email != null && code != null && !email.isEmpty() && !code.isEmpty()) { + System.out.println("测试"); if (Pattern.matches("^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$", email)) { - return authService.authLoginByEmail(email, code); + try { + Integer integer = Integer.valueOf(code); + return authService.authLoginByEmail(email, integer); + } catch (NumberFormatException e) { + return ResultUtil.error(ErrorCode.VERIFICATION_INVALID); + } } else { return ResultUtil.error(ErrorCode.PARAMETER_ERROR); } @@ -119,7 +126,15 @@ public class AuthController { * @since v1.1.0 */ @GetMapping("/auth/logout") - public BaseResponse authLogout() { - return null; + public BaseResponse authLogout(HttpServletRequest request) { + return authService.authLogout(request); + } + + @GetMapping("/auth/password") + public BaseResponse authChangePassword(@RequestBody @Validated UserChangePasswordVO userChangePasswordVO, HttpServletRequest request, @NotNull BindingResult bindingResult) { + if (bindingResult.hasErrors()) { + return ResultUtil.error(ErrorCode.REQUEST_BODY_ERROR, Processing.getValidatedErrorList(bindingResult)); + } + return authService.authChangePassword(request, userChangePasswordVO); } } diff --git a/src/main/java/com/jsl/oa/controllers/CustomController.java b/src/main/java/com/jsl/oa/controllers/CustomController.java index e6535d9..1f0ae09 100755 --- a/src/main/java/com/jsl/oa/controllers/CustomController.java +++ b/src/main/java/com/jsl/oa/controllers/CustomController.java @@ -1,25 +1,14 @@ package com.jsl.oa.controllers; -import com.jsl.oa.services.MailService; import com.jsl.oa.utils.BaseResponse; import com.jsl.oa.utils.ResultUtil; -import lombok.RequiredArgsConstructor; import org.springframework.boot.web.servlet.error.ErrorController; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController -@RequiredArgsConstructor public class CustomController implements ErrorController { - - private final MailService mailService; - - @RequestMapping("/") - public BaseResponse index() { - return ResultUtil.success("欢迎使用JSL-OA系统,服务器处于正常状态"); - } - @RequestMapping("/error") public ResponseEntity handleError() { return ResultUtil.error("PageNotFound", 404, "请求资源不存在"); diff --git a/src/main/java/com/jsl/oa/controllers/IndexController.java b/src/main/java/com/jsl/oa/controllers/IndexController.java new file mode 100644 index 0000000..b32ef33 --- /dev/null +++ b/src/main/java/com/jsl/oa/controllers/IndexController.java @@ -0,0 +1,14 @@ +package com.jsl.oa.controllers; + +import com.jsl.oa.utils.BaseResponse; +import com.jsl.oa.utils.ResultUtil; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class IndexController { + @RequestMapping("/") + public BaseResponse index() { + return ResultUtil.success("欢迎使用JSL-OA系统,服务器处于正常状态"); + } +} diff --git a/src/main/java/com/jsl/oa/exception/ProcessException.java b/src/main/java/com/jsl/oa/exception/ProcessException.java index cc2e854..de91c09 100755 --- a/src/main/java/com/jsl/oa/exception/ProcessException.java +++ b/src/main/java/com/jsl/oa/exception/ProcessException.java @@ -2,37 +2,40 @@ package com.jsl.oa.exception; import com.jsl.oa.utils.BaseResponse; import com.jsl.oa.utils.ResultUtil; +import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; +import org.springframework.dao.DuplicateKeyException; import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.web.HttpRequestMethodNotSupportedException; -import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; -import java.sql.SQLIntegrityConstraintViolationException; -import java.util.regex.Pattern; - -@ControllerAdvice +@Slf4j +@RestControllerAdvice public class ProcessException { - @ExceptionHandler(value = Exception.class) - public ResponseEntity businessException(@NotNull Exception e) { - e.printStackTrace(); - return ResultUtil.error("Exception", 500, "服务器异常"); - } - @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class) public ResponseEntity businessMethodNotAllowedException() { + log.debug("请求方法错误"); return ResultUtil.error("MethodNotAllowed", 405, "请求方法错误"); } - @ExceptionHandler(value = SQLIntegrityConstraintViolationException.class) - public ResponseEntity businessSQLIntegrityConstraintViolationException(@NotNull SQLIntegrityConstraintViolationException e) { - if (Pattern.matches(".*Duplicate entry.*", e.getMessage())) { - return ResultUtil.error("DuplicateEntry", 400, "数据重复"); - } else if (Pattern.matches(".*Cannot delete or update a parent row: a foreign key constraint fails.*", e.getMessage())) { - return ResultUtil.error("DataAssociation", 400, "数据存在关联,无法删除"); - } else { - return ResultUtil.error("DatabaseError", 400, "数据库异常"); - } + @ExceptionHandler(value = DuplicateKeyException.class) + public ResponseEntity businessDuplicateKeyException(@NotNull DuplicateKeyException e) { + log.debug(e.getMessage(), e); + return ResultUtil.error("DuplicateEntry", 400, "数据重复/外键约束"); + } + + @ExceptionHandler(value = HttpMessageNotReadableException.class) + public ResponseEntity businessHttpMessageNotReadableException(HttpMessageNotReadableException e) { + log.debug(e.getMessage(), e); + return ResultUtil.error("HttpMessageNotReadable", 400, "请求参数错误"); + } + + @ExceptionHandler(value = Exception.class) + public ResponseEntity businessException(@NotNull Exception e) { + log.error(e.getMessage(), e); + return ResultUtil.error("Exception", 500, "服务器异常"); } } diff --git a/src/main/java/com/jsl/oa/mapper/RoleMapper.java b/src/main/java/com/jsl/oa/mapper/RoleMapper.java index cc003cb..64e924c 100644 --- a/src/main/java/com/jsl/oa/mapper/RoleMapper.java +++ b/src/main/java/com/jsl/oa/mapper/RoleMapper.java @@ -1,10 +1,10 @@ package com.jsl.oa.mapper; -import com.jsl.oa.model.voData.RoleAddUserVO; -import com.jsl.oa.model.voData.RoleRemoveUserVO; +import com.jsl.oa.model.doData.RoleUserDO; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; @Mapper public interface RoleMapper { @@ -14,4 +14,7 @@ public interface RoleMapper { @Delete("delete from organize_oa.oa_role_user where uid=#{uid}") void roleRemoveUser(Long uid); + + @Select("SELECT * FROM organize_oa.oa_role_user WHERE uid=#{uid}") + RoleUserDO getRoleByUid(Long uid); } diff --git a/src/main/java/com/jsl/oa/mapper/UserMapper.java b/src/main/java/com/jsl/oa/mapper/UserMapper.java index 813cfa4..d199923 100755 --- a/src/main/java/com/jsl/oa/mapper/UserMapper.java +++ b/src/main/java/com/jsl/oa/mapper/UserMapper.java @@ -40,4 +40,7 @@ public interface UserMapper { UserDO getUserByJobId(String user); void userEditProfile(UserEditProfileVO userEditProfileVO); + + @Update("UPDATE organize_oa.oa_user SET password = #{newPassword} WHERE id = #{id}") + boolean updateUserPassword(Long id, String newPassword); } diff --git a/src/main/java/com/jsl/oa/model/voData/UserChangePasswordVO.java b/src/main/java/com/jsl/oa/model/voData/UserChangePasswordVO.java new file mode 100644 index 0000000..1fb8aa4 --- /dev/null +++ b/src/main/java/com/jsl/oa/model/voData/UserChangePasswordVO.java @@ -0,0 +1,15 @@ +package com.jsl.oa.model.voData; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +@Data +public class UserChangePasswordVO { + @NotBlank(message = "旧密码不能为空") + private String oldPassword; + @NotBlank(message = "新密码不能为空") + private String newPassword; + @NotBlank(message = "确认密码不能为空") + private String confirmPassword; +} diff --git a/src/main/java/com/jsl/oa/model/voData/UserLoginVO.java b/src/main/java/com/jsl/oa/model/voData/UserLoginVO.java index 917af80..c18d2df 100755 --- a/src/main/java/com/jsl/oa/model/voData/UserLoginVO.java +++ b/src/main/java/com/jsl/oa/model/voData/UserLoginVO.java @@ -1,6 +1,6 @@ package com.jsl.oa.model.voData; -import lombok.Getter; +import lombok.Data; import javax.validation.constraints.NotBlank; import javax.validation.constraints.Pattern; @@ -14,11 +14,11 @@ import javax.validation.constraints.Pattern; * @version v1.0.0 * @since v1.0.0 */ -@Getter +@Data public class UserLoginVO { @Pattern(regexp = "^[0-9A-Za-z_]+$", message = "支持用户名/手机号/工号登陆") @NotBlank(message = "用户名不能为空") - private String username; + private String user; @NotBlank(message = "密码不能为空") private String password; } diff --git a/src/main/java/com/jsl/oa/model/voData/UserReturnBackVO.java b/src/main/java/com/jsl/oa/model/voData/UserReturnBackVO.java index 55aaf1e..82eeb41 100755 --- a/src/main/java/com/jsl/oa/model/voData/UserReturnBackVO.java +++ b/src/main/java/com/jsl/oa/model/voData/UserReturnBackVO.java @@ -1,5 +1,6 @@ package com.jsl.oa.model.voData; +import com.jsl.oa.model.doData.RoleUserDO; import lombok.Getter; import lombok.Setter; import lombok.experimental.Accessors; @@ -25,4 +26,5 @@ public class UserReturnBackVO { private Short age; private Short sex; private String token; + private RoleUserDO role; } diff --git a/src/main/java/com/jsl/oa/services/AuthService.java b/src/main/java/com/jsl/oa/services/AuthService.java index 152033a..3ea905f 100755 --- a/src/main/java/com/jsl/oa/services/AuthService.java +++ b/src/main/java/com/jsl/oa/services/AuthService.java @@ -1,9 +1,12 @@ package com.jsl.oa.services; +import com.jsl.oa.model.voData.UserChangePasswordVO; import com.jsl.oa.model.voData.UserLoginVO; import com.jsl.oa.model.voData.UserRegisterVO; import com.jsl.oa.utils.BaseResponse; +import javax.servlet.http.HttpServletRequest; + /** *

用户认证服务接口

*
@@ -55,4 +58,23 @@ public interface AuthService { * @return {@link BaseResponse} */ BaseResponse authLoginSendEmailCode(String email); + + /** + *

用户修改密码

+ *
+ * 用户修改密码服务类操作 + * + * @param userChangePasswordVO 用户修改密码信息 + * @return {@link BaseResponse} + */ + BaseResponse authChangePassword(HttpServletRequest request, UserChangePasswordVO userChangePasswordVO); + + /** + *

用户登出

+ *
+ * 用户登出服务类操作 + * + * @return {@link BaseResponse} + */ + BaseResponse authLogout(HttpServletRequest request); } diff --git a/src/main/java/com/jsl/oa/services/impl/AuthServiceImpl.java b/src/main/java/com/jsl/oa/services/impl/AuthServiceImpl.java index ef8446f..b62cb53 100755 --- a/src/main/java/com/jsl/oa/services/impl/AuthServiceImpl.java +++ b/src/main/java/com/jsl/oa/services/impl/AuthServiceImpl.java @@ -2,8 +2,11 @@ package com.jsl.oa.services.impl; import com.jsl.oa.common.constant.BusinessConstants; import com.jsl.oa.exception.BusinessException; +import com.jsl.oa.mapper.RoleMapper; import com.jsl.oa.mapper.UserMapper; +import com.jsl.oa.model.doData.RoleUserDO; import com.jsl.oa.model.doData.UserDO; +import com.jsl.oa.model.voData.UserChangePasswordVO; import com.jsl.oa.model.voData.UserLoginVO; import com.jsl.oa.model.voData.UserRegisterVO; import com.jsl.oa.model.voData.UserReturnBackVO; @@ -11,11 +14,14 @@ import com.jsl.oa.services.AuthService; import com.jsl.oa.services.MailService; import com.jsl.oa.utils.*; import com.jsl.oa.utils.redis.EmailRedisUtil; +import com.jsl.oa.utils.redis.TokenRedisUtil; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; import org.mindrot.jbcrypt.BCrypt; import org.springframework.stereotype.Service; +import javax.servlet.http.HttpServletRequest; +import java.sql.Timestamp; import java.util.regex.Pattern; /** @@ -31,8 +37,11 @@ import java.util.regex.Pattern; @RequiredArgsConstructor public class AuthServiceImpl implements AuthService { private final UserMapper userMapper; + private final RoleMapper roleMapper; + private final MailService mailService; private final EmailRedisUtil emailRedisUtil; + private final TokenRedisUtil tokenRedisUtil; @Override public BaseResponse authRegister(@NotNull UserRegisterVO userRegisterVO) { @@ -71,34 +80,23 @@ public class AuthServiceImpl implements AuthService { public BaseResponse authLogin(@NotNull UserLoginVO userLoginVO) { // 检查用户是否存在 UserDO userDO; - if (Pattern.matches("^[0-9A-Za-z_]{3,40}$", userLoginVO.getUsername())) { + if (Pattern.matches("^[0-9A-Za-z_]{3,40}$", userLoginVO.getUser())) { // 是否为用户名 - userDO = userMapper.getUserInfoByUsername(userLoginVO.getUsername()); - } else if (Pattern.matches("^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\\d{8}$", userLoginVO.getUsername())) { + userDO = userMapper.getUserInfoByUsername(userLoginVO.getUser()); + } else if (Pattern.matches("^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\\d{8}$", userLoginVO.getUser())) { // 是否为手机号 - userDO = userMapper.getUserInfoByPhone(userLoginVO.getUsername()); - } else if (Pattern.matches("^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$", userLoginVO.getUsername())) { + userDO = userMapper.getUserInfoByPhone(userLoginVO.getUser()); + } else if (Pattern.matches("^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$", userLoginVO.getUser())) { // 是否为邮箱 return ResultUtil.error(ErrorCode.EMAIL_LOGIN_NOT_SUPPORT); } else { // 工号 - userDO = userMapper.getUserByJobId(userLoginVO.getUsername()); + userDO = userMapper.getUserByJobId(userLoginVO.getUser()); } if (userDO != null) { // 获取用户并登陆 if (BCrypt.checkpw(userLoginVO.getPassword(), userDO.getPassword())) { - UserReturnBackVO userReturnBackVO = new UserReturnBackVO(); - // 授权 Token - String token = JwtUtil.generateToken(userDO.getId()); - userReturnBackVO.setAddress(userDO.getAddress()) - .setAge(userDO.getAge()) - .setEmail(userDO.getEmail()) - .setJobId(userDO.getJobId()) - .setPhone(userDO.getPhone()) - .setSex(userDO.getSex()) - .setUsername(userDO.getUsername()) - .setToken(token); - return ResultUtil.success("登陆成功", userReturnBackVO); + return this.encapsulateDisplayContent(userDO); } else { return ResultUtil.error(ErrorCode.WRONG_PASSWORD); } @@ -117,18 +115,7 @@ public class AuthServiceImpl implements AuthService { if (emailRedisUtil.delData(BusinessConstants.BUSINESS_LOGIN, email)) { // 邮箱获取用户 UserDO userDO = userMapper.getUserInfoByEmail(email); - // 授权 Token - String token = JwtUtil.generateToken(userDO.getId()); - UserReturnBackVO userReturnBackVO = new UserReturnBackVO(); - userReturnBackVO.setAddress(userDO.getAddress()) - .setAge(userDO.getAge()) - .setEmail(userDO.getEmail()) - .setJobId(userDO.getJobId()) - .setPhone(userDO.getPhone()) - .setSex(userDO.getSex()) - .setUsername(userDO.getUsername()) - .setToken(token); - return ResultUtil.success("登陆成功", userReturnBackVO); + return this.encapsulateDisplayContent(userDO); } else { return ResultUtil.error(ErrorCode.DATABASE_DELETE_ERROR); } @@ -159,4 +146,76 @@ public class AuthServiceImpl implements AuthService { return ResultUtil.error(ErrorCode.USER_NOT_EXIST); } } + + @Override + public BaseResponse authChangePassword(HttpServletRequest request, @NotNull UserChangePasswordVO userChangePasswordVO) { + // 检查新密码输入无误 + if (!userChangePasswordVO.getNewPassword().equals(userChangePasswordVO.getConfirmPassword())) { + return ResultUtil.error(ErrorCode.PASSWORD_NOT_SAME); + } + // 检查用户 + UserDO userDO = userMapper.getUserById(Processing.getAuthHeader(request)); + if (userDO != null) { + // 检查旧密码 + if (BCrypt.checkpw(userChangePasswordVO.getOldPassword(), userDO.getPassword())) { + // 更新密码 + if (userMapper.updateUserPassword(userDO.getId(), BCrypt.hashpw(userChangePasswordVO.getNewPassword(), BCrypt.gensalt()))) { + return ResultUtil.success("修改成功"); + } else { + return ResultUtil.error(ErrorCode.DATABASE_UPDATE_ERROR); + } + } else { + return ResultUtil.error(ErrorCode.WRONG_PASSWORD); + } + } else { + return ResultUtil.error(ErrorCode.USER_NOT_EXIST); + } + } + + @Override + public BaseResponse authLogout(HttpServletRequest request) { + // 获取用户 + UserDO userDO = userMapper.getUserById(Processing.getAuthHeader(request)); + // 删除Token + if (tokenRedisUtil.delData(BusinessConstants.BUSINESS_LOGIN, userDO.getId().toString())) { + return ResultUtil.success("登出成功"); + } else { + return ResultUtil.error(ErrorCode.DATABASE_DELETE_ERROR); + } + } + + /** + *

封装返回内容

+ *
+ * 封装返回内容 + * + * @param userDO 用户信息 + * @return {@link BaseResponse} + */ + private @NotNull BaseResponse encapsulateDisplayContent(@NotNull UserDO userDO) { + // 授权 Token + String token = JwtUtil.generateToken(userDO.getId()); + UserReturnBackVO userReturnBackVO = new UserReturnBackVO(); + // Token 上传到 Redis + tokenRedisUtil.setData(BusinessConstants.BUSINESS_LOGIN, userDO.getId().toString(), token, 1440); + // 获取用户角色 + RoleUserDO getUserRole = roleMapper.getRoleByUid(userDO.getId()); + if (getUserRole == null) { + getUserRole = new RoleUserDO(); + getUserRole.setRid(0L) + .setCreatedAt(new Timestamp(System.currentTimeMillis())); + } else { + getUserRole.setUid(null); + } + userReturnBackVO.setAddress(userDO.getAddress()) + .setAge(userDO.getAge()) + .setEmail(userDO.getEmail()) + .setJobId(userDO.getJobId()) + .setPhone(userDO.getPhone()) + .setSex(userDO.getSex()) + .setUsername(userDO.getUsername()) + .setToken(token) + .setRole(getUserRole); + return ResultUtil.success("登陆成功", userReturnBackVO); + } } diff --git a/src/main/java/com/jsl/oa/utils/ErrorCode.java b/src/main/java/com/jsl/oa/utils/ErrorCode.java index 2760047..1eb2577 100755 --- a/src/main/java/com/jsl/oa/utils/ErrorCode.java +++ b/src/main/java/com/jsl/oa/utils/ErrorCode.java @@ -13,7 +13,9 @@ public enum ErrorCode { UNAUTHORIZED("Unauthorized", 40100, "未授权"), TOKEN_EXPIRED("TokenExpired", 40101, "Token已过期"), VERIFICATION_INVALID("VerificationInvalid", 40102, "验证码无效"), + TOKEN_NOT_EXIST("TokenNotExist", 40103, "Token不存在"), EMAIL_LOGIN_NOT_SUPPORT("EmailLoginNotSupport", 40300, "请使用邮箱登陆"), + PASSWORD_NOT_SAME("PasswordNotSame", 40301, "两次密码不一致"), DATABASE_INSERT_ERROR("DatabaseInsertError", 50010, "数据库插入错误"), DATABASE_UPDATE_ERROR("DatabaseUpdateError", 50011, "数据库更新错误"), DATABASE_DELETE_ERROR("DatabaseDeleteError", 50012, "数据库删除错误"), diff --git a/src/main/java/com/jsl/oa/utils/JwtUtil.java b/src/main/java/com/jsl/oa/utils/JwtUtil.java index 20914fe..146a253 100755 --- a/src/main/java/com/jsl/oa/utils/JwtUtil.java +++ b/src/main/java/com/jsl/oa/utils/JwtUtil.java @@ -6,6 +6,7 @@ import io.jsonwebtoken.Jws; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.security.Keys; +import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import java.security.Key; @@ -21,6 +22,7 @@ import java.util.regex.Pattern; * @see com.jsl.oa.config.JwtFilter * @since v1.1.0 */ +@Slf4j public class JwtUtil { private static final long EXPIRATION_TIME = 86400000; @@ -52,9 +54,10 @@ public class JwtUtil { try { Long getTokenInUserId = getUserId(token); // 验证用户名是否匹配 + log.debug("Token值" + getTokenInUserId.toString()); return Pattern.matches("^[0-9]+$", getTokenInUserId.toString()); } catch (Exception e) { - e.printStackTrace(); + log.debug("Token验证失败", e); return false; } } @@ -77,8 +80,9 @@ public class JwtUtil { long userId; try { userId = Long.parseLong(claimsJws.getBody().getSubject()); + log.debug("用户ID" + userId); } catch (NumberFormatException exception) { - exception.printStackTrace(); + log.debug("用户ID格式错误", exception); throw new NumberFormatException("用户ID格式错误"); } return userId; diff --git a/src/main/java/com/jsl/oa/utils/Processing.java b/src/main/java/com/jsl/oa/utils/Processing.java index 8d64497..d7a3d30 100755 --- a/src/main/java/com/jsl/oa/utils/Processing.java +++ b/src/main/java/com/jsl/oa/utils/Processing.java @@ -1,9 +1,11 @@ package com.jsl.oa.utils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.springframework.validation.BindingResult; import org.springframework.validation.ObjectError; +import javax.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.Random; @@ -126,6 +128,24 @@ public class Processing { return result.toString(); } + /** + *

获取Authorization Header

+ *
+ * 用于获取Authorization Header + * + * @param request 请求 + */ + public static @Nullable Long getAuthHeader(@NotNull HttpServletRequest request) { + String token = request.getHeader("Authorization"); + if (token == null || token.isEmpty()) { + return null; + } else { + // 解析Bearer后面的令牌 + token = token.replace("Bearer ", ""); + return JwtUtil.getUserId(token); + } + } + private static char getCharFromIndex(int index) { // 生成字符集合,可以根据需要自定义 String charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; diff --git a/src/main/java/com/jsl/oa/utils/ResultUtil.java b/src/main/java/com/jsl/oa/utils/ResultUtil.java index c06a441..99c6636 100755 --- a/src/main/java/com/jsl/oa/utils/ResultUtil.java +++ b/src/main/java/com/jsl/oa/utils/ResultUtil.java @@ -1,38 +1,57 @@ package com.jsl.oa.utils; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; import org.springframework.http.ResponseEntity; +@Slf4j public class ResultUtil { - public static BaseResponse success() { + @Contract(" -> new") + public static @NotNull BaseResponse success() { + log.debug("请求接口成功"); return new BaseResponse("Success", 200, "操作成功", null); } - public static BaseResponse success(String message) { + @Contract("_ -> new") + public static @NotNull BaseResponse success(String message) { + log.debug("请求接口成功"); return new BaseResponse("Success", 200, message, null); } - public static BaseResponse success(Object data) { + @Contract(value = "_ -> new", pure = true) + public static @NotNull BaseResponse success(Object data) { + log.debug("请求接口成功"); return new BaseResponse("Success", 200, "操作成功", data); } - public static BaseResponse success(String message, Object data) { + @Contract(value = "_, _ -> new", pure = true) + public static @NotNull BaseResponse success(String message, Object data) { + log.debug("请求接口成功"); return new BaseResponse("Success", 200, message, data); } - public static BaseResponse error(ErrorCode errorCode) { + @Contract("_ -> new") + public static @NotNull BaseResponse error(@NotNull ErrorCode errorCode) { + log.debug("请求接口错误[" + errorCode.getCode() + "] " + errorCode.getMessage()); return new BaseResponse(errorCode.getOutput(), errorCode.getCode(), errorCode.getMessage()); } - public static BaseResponse error(ErrorCode errorCode, Object data) { + @Contract("_, _ -> new") + public static @NotNull BaseResponse error(@NotNull ErrorCode errorCode, Object data) { + log.debug("请求接口错误[" + errorCode.getCode() + "] " + errorCode.getMessage()); return new BaseResponse(errorCode.getOutput(), errorCode.getCode(), errorCode.getMessage(), data); } - public static BaseResponse error(String output, Integer code, String message, Object data) { + @Contract(value = "_, _, _, _ -> new", pure = true) + public static @NotNull BaseResponse error(String output, Integer code, String message, Object data) { + log.debug("请求接口错误[" + code + "] " + message); return new BaseResponse(output, code, message, data); } - public static ResponseEntity error(String output, Integer code, String message) { + public static @NotNull ResponseEntity error(String output, Integer code, String message) { + log.debug("请求接口错误[" + code + "] " + message); return ResponseEntity.status(code) .body(new BaseResponse(output, code, message)); } diff --git a/src/main/java/com/jsl/oa/utils/redis/TokenRedisUtil.java b/src/main/java/com/jsl/oa/utils/redis/TokenRedisUtil.java new file mode 100644 index 0000000..a92296b --- /dev/null +++ b/src/main/java/com/jsl/oa/utils/redis/TokenRedisUtil.java @@ -0,0 +1,51 @@ +package com.jsl.oa.utils.redis; + +import com.jsl.oa.common.constant.BusinessConstants; +import com.jsl.oa.common.constant.RedisConstant; +import com.jsl.oa.config.redis.RedisOperating; +import org.jetbrains.annotations.NotNull; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +@Component +public class TokenRedisUtil extends RedisOperating { + public TokenRedisUtil(RedisTemplate redisTemplate, StringRedisTemplate stringRedisTemplate) { + super(redisTemplate, stringRedisTemplate); + } + + @Override + public Long getExpiredAt(@NotNull BusinessConstants businessConstants, String field) { + String key = RedisConstant.TYPE_AUTH + RedisConstant.TABLE_TOKEN + businessConstants.getValue() + field; + return redisTemplate.getExpire(key); + } + + @Override + public Boolean delData(@NotNull BusinessConstants businessConstants, String field) { + String key = RedisConstant.TYPE_AUTH + RedisConstant.TABLE_TOKEN + businessConstants.getValue() + field; + return redisTemplate.delete(key); + } + + @Override + public R getData(@NotNull BusinessConstants businessConstants, String field) { + String key = RedisConstant.TYPE_AUTH + RedisConstant.TABLE_TOKEN + businessConstants.getValue() + field; + return redisTemplate.opsForValue().get(key); + } + + @Override + public Boolean setData(@NotNull BusinessConstants businessConstants, String field, R value, Integer time) { + // 处理数据 + String key = RedisConstant.TYPE_AUTH + RedisConstant.TABLE_TOKEN + businessConstants.getValue() + field; + redisTemplate.opsForValue().set(key, value); + redisTemplate.expire(key, time, TimeUnit.MINUTES); + return true; + } + + public List getList(@NotNull BusinessConstants businessConstants) { + String key = RedisConstant.TYPE_AUTH + RedisConstant.TABLE_TOKEN + businessConstants.getValue() + "*"; + return this.getList(key); + } +}