diff --git a/.gitignore b/.gitignore
index 48e6007..feff169 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,3 +34,4 @@ build/
### 自定义 ###
*.pdf
+/src/main/resources/application-dev.yml
diff --git a/mysql/organize_oa.sql b/mysql/organize_oa.sql
index 0b37dd7..8d09fa0 100644
--- a/mysql/organize_oa.sql
+++ b/mysql/organize_oa.sql
@@ -195,7 +195,7 @@ CREATE TABLE `oa_user`
`account_no_expired` tinyint(1) NOT NULL DEFAULT '1' COMMENT '账户是否过期',
`credentials_no_expired` tinyint(1) NOT NULL DEFAULT '0' COMMENT '密码是否过期',
`recommend` tinyint(1) NOT NULL DEFAULT '0' COMMENT '账户是否被推荐',
- `account_no_locked` tinyint(1) NOT NULL COMMENT '账户是否被锁定',
+ `account_no_locked` tinyint(1) NOT NULL DEFAULT '1' COMMENT '账户是否被锁定',
`description` text COMMENT '个人简介',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` timestamp NULL DEFAULT NULL COMMENT '更新时间'
diff --git a/pom.xml b/pom.xml
index 0292c13..32fe857 100644
--- a/pom.xml
+++ b/pom.xml
@@ -103,6 +103,22 @@
org.springframework.boot
spring-boot-starter-data-redis
+
+ org.jetbrains
+ annotations
+ 24.1.0
+ compile
+
+
+
+ org.springframework.boot
+ spring-boot-starter-mail
+
+
+
+ com.google.code.gson
+ gson
+
diff --git a/src/main/java/com/jsl/oa/config/JwtFilter.java b/src/main/java/com/jsl/oa/config/JwtFilter.java
new file mode 100644
index 0000000..bfa2883
--- /dev/null
+++ b/src/main/java/com/jsl/oa/config/JwtFilter.java
@@ -0,0 +1,81 @@
+package com.jsl.oa.config;
+
+import com.google.gson.Gson;
+import com.jsl.oa.utils.ErrorCode;
+import com.jsl.oa.utils.JwtUtil;
+import com.jsl.oa.utils.ResultUtil;
+import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
+import org.jetbrains.annotations.NotNull;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * JWT过滤器
+ *
+ * 用于JWT的过滤器
+ *
+ * @since v1.1.0
+ * @version v1.1.0
+ * @author 筱锋xiao_lfeng
+ */
+public class JwtFilter extends BasicHttpAuthenticationFilter {
+
+ /**
+ * 判断用户Token
+ *
+ * 判断用户Token是否存在,如果存在则进行验证
+ *
+ * @param request 请求
+ * @param response 响应
+ * @param mappedValue 映射值
+ * @return {@link Boolean}
+ */
+ @Override
+ protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
+ // 判断是否存在Authorization Header
+ String token = getAuthzHeader(request);
+ if (token == null || token.isEmpty()) {
+ return false; // 未提供Token,拒绝访问
+ } else {
+ // 解析Bearer后面的令牌
+ token = token.replace("Bearer ", "");
+ System.out.println(token);
+ return JwtUtil.verify(token);
+ }
+ }
+
+ /**
+ * 访问被拒绝时
+ *
+ * 当访问被拒绝时,会调用此方法
+ *
+ * @param request 请求
+ * @param response 响应
+ * @param mappedValue 映射值
+ * @return {@link Boolean}
+ * @throws Exception 异常
+ */
+ @Override
+ protected boolean onAccessDenied(ServletRequest request, @NotNull ServletResponse response, Object mappedValue) throws Exception {
+ Gson gson = new Gson();
+ response.setContentType("application/json;charset=UTF-8");
+ response.getWriter().println(gson.toJson(ResultUtil.error(ErrorCode.UNAUTHORIZED)));
+ return false;
+ }
+
+ /**
+ * 获取Authorization Header
+ *
+ * 用于获取Authorization Header
+ *
+ * @param request 请求
+ * @return {@link String}
+ */
+ @Override
+ protected String getAuthzHeader(ServletRequest request) {
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+ return httpRequest.getHeader("Authorization");
+ }
+}
diff --git a/src/main/java/com/jsl/oa/config/JwtToken.java b/src/main/java/com/jsl/oa/config/JwtToken.java
deleted file mode 100644
index c3dde62..0000000
--- a/src/main/java/com/jsl/oa/config/JwtToken.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.jsl.oa.config;
-
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-import org.apache.shiro.authc.AuthenticationToken;
-
-@Getter
-@RequiredArgsConstructor
-public class JwtToken implements AuthenticationToken {
-
- private final String token;
- private final String username;
-
- @Override
- public Object getPrincipal() {
- return token;
- }
-
- @Override
- public Object getCredentials() {
- return token;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/jsl/oa/config/MailConfiguration.java b/src/main/java/com/jsl/oa/config/MailConfiguration.java
new file mode 100644
index 0000000..432255f
--- /dev/null
+++ b/src/main/java/com/jsl/oa/config/MailConfiguration.java
@@ -0,0 +1,47 @@
+package com.jsl.oa.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.JavaMailSenderImpl;
+
+import java.util.Properties;
+
+/**
+ * 邮件配置类
+ *
+ * 用于配置邮件发送相关信息
+ *
+ * @since v1.1.0
+ * @version v1.1.0
+ * @author 筱锋xiao_lfeng
+ */
+@Configuration
+public class MailConfiguration {
+
+ @Value("${spring.mail.host}")
+ private String emailHost;
+ @Value("${spring.mail.username}")
+ private String emailUsername;
+ @Value("${spring.mail.password}")
+ private String emailPassword;
+
+ @Bean
+ public JavaMailSender javaMailSender() {
+ JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
+ mailSender.setDefaultEncoding("UTF-8");
+ mailSender.setHost(emailHost);
+ mailSender.setPort(25); // 你的邮件服务器端口
+ mailSender.setUsername(emailUsername);
+ mailSender.setPassword(emailPassword);
+
+ Properties props = mailSender.getJavaMailProperties();
+ props.put("mail.transport.protocol", "smtp");
+ props.put("mail.smtp.auth", "true");
+ props.put("mail.smtp.starttls.enable", "true");
+ props.put("mail.debug", "true");
+
+ return mailSender;
+ }
+}
diff --git a/src/main/java/com/jsl/oa/config/MyRealm.java b/src/main/java/com/jsl/oa/config/MyRealm.java
deleted file mode 100644
index 740eed8..0000000
--- a/src/main/java/com/jsl/oa/config/MyRealm.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.jsl.oa.config;
-
-import com.jsl.oa.model.doData.UserDO;
-import com.jsl.oa.services.UserService;
-import lombok.RequiredArgsConstructor;
-import org.apache.shiro.authc.*;
-import org.apache.shiro.authz.AuthorizationInfo;
-import org.apache.shiro.realm.AuthorizingRealm;
-import org.apache.shiro.subject.PrincipalCollection;
-
-@RequiredArgsConstructor
-public class MyRealm extends AuthorizingRealm {
-
- private final UserService userService;
-
- /**
- * 授权
- * @param principalCollection 令牌
- * @return 授权信息
- */
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
- return null;
- }
-
- /**
- * 认证
- * @param authenticationToken 令牌
- * @return 认证信息
- * @throws AuthenticationException 认证异常
- */
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
- JwtToken jwtToken = (JwtToken) authenticationToken;
- String username = jwtToken.getUsername();
-
- // 从数据库获取用户信息
- UserDO userDO = userService.getUserInfoByUsername(username);
- if (userDO == null) {
- throw new UnknownAccountException("用户不存在");
- } else if (!userDO.getAccountNoLocked()) {
- throw new LockedAccountException("用户已被锁定");
- } else if (!userDO.getEnabled()) {
- throw new DisabledAccountException("用户已被禁用");
- } else if (!userDO.getAccountNoExpired()) {
- throw new ExpiredCredentialsException("用户已过期");
- }
-
- return new SimpleAuthenticationInfo(username, jwtToken.getCredentials(), getName());
- }
-}
diff --git a/src/main/java/com/jsl/oa/config/shiro/MyRealm.java b/src/main/java/com/jsl/oa/config/shiro/MyRealm.java
new file mode 100644
index 0000000..78e4ff6
--- /dev/null
+++ b/src/main/java/com/jsl/oa/config/shiro/MyRealm.java
@@ -0,0 +1,40 @@
+package com.jsl.oa.config.shiro;
+
+import com.jsl.oa.services.UserService;
+import lombok.RequiredArgsConstructor;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.jetbrains.annotations.NotNull;
+
+@RequiredArgsConstructor
+public class MyRealm extends AuthorizingRealm {
+
+ private final UserService userService;
+
+ /**
+ * 授权
+ *
+ * @return 授权信息
+ */
+ @Override
+ protected AuthorizationInfo doGetAuthorizationInfo(@NotNull PrincipalCollection principals) {
+ return null;
+ }
+
+
+ /**
+ * 认证
+ *
+ * @param authenticationToken 令牌
+ * @return 认证信息
+ * @throws AuthenticationException 认证异常
+ */
+ @Override
+ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
+ return null;
+ }
+}
diff --git a/src/main/java/com/jsl/oa/config/ShiroConfiguration.java b/src/main/java/com/jsl/oa/config/shiro/ShiroConfiguration.java
similarity index 70%
rename from src/main/java/com/jsl/oa/config/ShiroConfiguration.java
rename to src/main/java/com/jsl/oa/config/shiro/ShiroConfiguration.java
index ec861a6..b1779e2 100644
--- a/src/main/java/com/jsl/oa/config/ShiroConfiguration.java
+++ b/src/main/java/com/jsl/oa/config/shiro/ShiroConfiguration.java
@@ -1,5 +1,6 @@
-package com.jsl.oa.config;
+package com.jsl.oa.config.shiro;
+import com.jsl.oa.config.JwtFilter;
import com.jsl.oa.services.UserService;
import lombok.RequiredArgsConstructor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
@@ -7,6 +8,7 @@ import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -24,11 +26,19 @@ public class ShiroConfiguration {
// 配置过滤器规则
Map filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/auth/**", "anon"); // 登录接口允许匿名访问
+ filterChainDefinitionMap.put("/unauthorized", "anon"); // 未授权接口允许匿名访问
+ filterChainDefinitionMap.put("/", "anon"); // 首页允许匿名访问
+ filterChainDefinitionMap.put("/**/**", "jwt"); // 其他接口一律拦截(需要Token)
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
- // 设置登录接口
+ // 设置未登陆响应接口
shiroFilterFactoryBean.setLoginUrl("/unauthorized");
+
+ // 添加JWT过滤器
+ Map filters = new LinkedHashMap<>();
+ filters.put("jwt", new JwtFilter()); // 配置自定义的JWT过滤器
+ shiroFilterFactoryBean.setFilters(filters);
return shiroFilterFactoryBean;
}
diff --git a/src/main/java/com/jsl/oa/controllers/AuthController.java b/src/main/java/com/jsl/oa/controllers/AuthController.java
index c7bb20a..cfbd6fd 100644
--- a/src/main/java/com/jsl/oa/controllers/AuthController.java
+++ b/src/main/java/com/jsl/oa/controllers/AuthController.java
@@ -8,18 +8,19 @@ import com.jsl.oa.utils.ErrorCode;
import com.jsl.oa.utils.Processing;
import com.jsl.oa.utils.ResultUtil;
import lombok.RequiredArgsConstructor;
+import org.jetbrains.annotations.NotNull;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.text.ParseException;
+import java.util.regex.Pattern;
/**
* 用户认证控制器
*
* 用户认证控制器,包含用户注册、用户登录、用户登出接口
*
- * @since v1.0.0
* @version v1.1.0
* @see AuthService
* @see UserRegisterVO
@@ -28,6 +29,7 @@ import java.text.ParseException;
* @see ErrorCode
* @see Processing
* @see ResultUtil
+ * @since v1.0.0
*/
@RestController
@RequiredArgsConstructor
@@ -39,12 +41,12 @@ public class AuthController {
*
* 用户注册接口
*
- * @since v1.0.0
* @return {@link BaseResponse}
* @author 筱锋xiao_lfeng
+ * @since v1.0.0
*/
@PostMapping("/auth/register")
- public BaseResponse authRegister(@RequestBody @Validated UserRegisterVO userRegisterVO, BindingResult bindingResult) throws ParseException {
+ public BaseResponse authRegister(@RequestBody @Validated UserRegisterVO userRegisterVO, @NotNull BindingResult bindingResult) throws ParseException {
// 判断是否有参数错误
if (bindingResult.hasErrors()) {
return ResultUtil.error(ErrorCode.REQUEST_BODY_ERROR, Processing.getValidatedErrorList(bindingResult));
@@ -57,13 +59,14 @@ public class AuthController {
*
* 用户登录接口
*
- * @since v1.0.0
- * @param userLoginVO 用户登录信息
+ * @param userLoginVO 用户登录信息
+ * @param bindingResult 参数校验结果
* @return {@link BaseResponse}
* @author 176yunxuan
+ * @since v1.0.0
*/
@GetMapping("/auth/login")
- public BaseResponse authLogin(@RequestBody @Validated UserLoginVO userLoginVO, BindingResult bindingResult){
+ public BaseResponse authLogin(@RequestBody @Validated UserLoginVO userLoginVO, @NotNull BindingResult bindingResult) {
// 判断是否有参数错误
if (bindingResult.hasErrors()) {
return ResultUtil.error(ErrorCode.REQUEST_BODY_ERROR, Processing.getValidatedErrorList(bindingResult));
@@ -71,6 +74,38 @@ public class AuthController {
return authService.authLogin(userLoginVO);
}
+ /**
+ * 用户邮箱登录
+ *
+ * 用户邮箱登录接口
+ *
+ * @param email 用户登陆邮箱
+ * @return {@link BaseResponse}
+ * @author 筱锋xiao_lfeng
+ * @since v1.1.0
+ */
+ @GetMapping("/auth/login/email")
+ public BaseResponse authLoginByEmail(@RequestParam String email) {
+ if (email != null) {
+ if (Pattern.matches("^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$", email)) {
+ return authService.authLoginByEmail(email);
+ } else {
+ return ResultUtil.error(ErrorCode.PARAMETER_ERROR);
+ }
+ } else {
+ return ResultUtil.error(ErrorCode.PARAMETER_ERROR);
+ }
+ }
+
+ /**
+ * 用户登出
+ *
+ * 用户登出接口
+ *
+ * @return {@link BaseResponse}
+ * @since v1.1.0
+ */
+ @GetMapping("/auth/logout")
public BaseResponse authLogout() {
return null;
}
diff --git a/src/main/java/com/jsl/oa/controllers/CustomController.java b/src/main/java/com/jsl/oa/controllers/CustomController.java
index 7f62c84..e6535d9 100644
--- a/src/main/java/com/jsl/oa/controllers/CustomController.java
+++ b/src/main/java/com/jsl/oa/controllers/CustomController.java
@@ -1,15 +1,20 @@
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系统,服务器处于正常状态");
diff --git a/src/main/java/com/jsl/oa/controllers/InfoController.java b/src/main/java/com/jsl/oa/controllers/InfoController.java
index 0fb29d6..008c89a 100644
--- a/src/main/java/com/jsl/oa/controllers/InfoController.java
+++ b/src/main/java/com/jsl/oa/controllers/InfoController.java
@@ -1,21 +1,8 @@
package com.jsl.oa.controllers;
-import com.jsl.oa.model.voData.UserLoginVO;
-import com.jsl.oa.model.voData.UserRegisterVO;
-import com.jsl.oa.services.AuthService;
-import com.jsl.oa.utils.BaseResponse;
-import com.jsl.oa.utils.ErrorCode;
-import com.jsl.oa.utils.Processing;
-import com.jsl.oa.utils.ResultUtil;
import lombok.RequiredArgsConstructor;
-import org.springframework.validation.BindingResult;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
-import java.text.ParseException;
-
@RestController
@RequiredArgsConstructor
public class InfoController {
diff --git a/src/main/java/com/jsl/oa/controllers/PermissionController.java b/src/main/java/com/jsl/oa/controllers/PermissionController.java
index 64ea36d..b305e0c 100644
--- a/src/main/java/com/jsl/oa/controllers/PermissionController.java
+++ b/src/main/java/com/jsl/oa/controllers/PermissionController.java
@@ -1,21 +1,8 @@
package com.jsl.oa.controllers;
-import com.jsl.oa.model.voData.UserLoginVO;
-import com.jsl.oa.model.voData.UserRegisterVO;
-import com.jsl.oa.services.AuthService;
-import com.jsl.oa.utils.BaseResponse;
-import com.jsl.oa.utils.ErrorCode;
-import com.jsl.oa.utils.Processing;
-import com.jsl.oa.utils.ResultUtil;
import lombok.RequiredArgsConstructor;
-import org.springframework.validation.BindingResult;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
-import java.text.ParseException;
-
@RestController
@RequiredArgsConstructor
public class PermissionController {
diff --git a/src/main/java/com/jsl/oa/controllers/ProjectController.java b/src/main/java/com/jsl/oa/controllers/ProjectController.java
index 3e1ac22..ee41730 100644
--- a/src/main/java/com/jsl/oa/controllers/ProjectController.java
+++ b/src/main/java/com/jsl/oa/controllers/ProjectController.java
@@ -1,21 +1,8 @@
package com.jsl.oa.controllers;
-import com.jsl.oa.model.voData.UserLoginVO;
-import com.jsl.oa.model.voData.UserRegisterVO;
-import com.jsl.oa.services.AuthService;
-import com.jsl.oa.utils.BaseResponse;
-import com.jsl.oa.utils.ErrorCode;
-import com.jsl.oa.utils.Processing;
-import com.jsl.oa.utils.ResultUtil;
import lombok.RequiredArgsConstructor;
-import org.springframework.validation.BindingResult;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
-import java.text.ParseException;
-
@RestController
@RequiredArgsConstructor
public class ProjectController {
diff --git a/src/main/java/com/jsl/oa/controllers/RoleController.java b/src/main/java/com/jsl/oa/controllers/RoleController.java
index 3f0df63..8466221 100644
--- a/src/main/java/com/jsl/oa/controllers/RoleController.java
+++ b/src/main/java/com/jsl/oa/controllers/RoleController.java
@@ -1,21 +1,8 @@
package com.jsl.oa.controllers;
-import com.jsl.oa.model.voData.UserLoginVO;
-import com.jsl.oa.model.voData.UserRegisterVO;
-import com.jsl.oa.services.AuthService;
-import com.jsl.oa.utils.BaseResponse;
-import com.jsl.oa.utils.ErrorCode;
-import com.jsl.oa.utils.Processing;
-import com.jsl.oa.utils.ResultUtil;
import lombok.RequiredArgsConstructor;
-import org.springframework.validation.BindingResult;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
-import java.text.ParseException;
-
@RestController
@RequiredArgsConstructor
diff --git a/src/main/java/com/jsl/oa/dao/UserDAO.java b/src/main/java/com/jsl/oa/dao/UserDAO.java
index 4c0357f..d26c795 100644
--- a/src/main/java/com/jsl/oa/dao/UserDAO.java
+++ b/src/main/java/com/jsl/oa/dao/UserDAO.java
@@ -13,6 +13,15 @@ public class UserDAO {
private final UserMapper userMapper;
+ /**
+ * 用户名获取用户信息
+ *
+ * 根据用户名获取用户信息
+ *
+ * @param username 用户名
+ * @author 筱锋xiao_lfeng
+ * @return {@link UserDO}
+ */
public UserDO getUserInfoByUsername(String username) {
UserDO userDO = null;
// 从 Redis 获取数据
diff --git a/src/main/java/com/jsl/oa/mapper/UserMapper.java b/src/main/java/com/jsl/oa/mapper/UserMapper.java
index da5c88d..8de0aa9 100644
--- a/src/main/java/com/jsl/oa/mapper/UserMapper.java
+++ b/src/main/java/com/jsl/oa/mapper/UserMapper.java
@@ -37,4 +37,7 @@ public interface UserMapper {
@Select("select * from organize_oa.oa_user where id = #{id}")
UserDO getUserById(Long id);
+
+ @Select("select * from organize_oa.oa_user where email = #{email}")
+ UserDO getUserInfoByEmail(String email);
}
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 25c4ce6..f62e1f8 100644
--- a/src/main/java/com/jsl/oa/model/voData/UserLoginVO.java
+++ b/src/main/java/com/jsl/oa/model/voData/UserLoginVO.java
@@ -16,8 +16,9 @@ import javax.validation.constraints.Pattern;
*/
@Getter
public class UserLoginVO {
- @Pattern(regexp = "^[0-9A-Z]+$", message = "工号格式错误")
- private String jobId;
+ @Pattern(regexp = "^[0-9A-Za-z_]+$", message = "支持用户名/手机号/工号登陆")
+ @NotBlank(message = "用户名不能为空")
+ private String user;
@NotBlank(message = "密码不能为空")
private String password;
}
diff --git a/src/main/java/com/jsl/oa/model/voData/UserRegisterVO.java b/src/main/java/com/jsl/oa/model/voData/UserRegisterVO.java
index 6745d96..7b6df82 100644
--- a/src/main/java/com/jsl/oa/model/voData/UserRegisterVO.java
+++ b/src/main/java/com/jsl/oa/model/voData/UserRegisterVO.java
@@ -1,9 +1,9 @@
package com.jsl.oa.model.voData;
import lombok.Getter;
+import lombok.Setter;
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.Pattern;
+import javax.validation.constraints.*;
/**
* 用户注册自定义实体类
@@ -12,29 +12,34 @@ import javax.validation.constraints.Pattern;
*
* @author 筱锋xiao_lfeng
* @version v1.0.0
- * @since v1.0.0
+ * @since v1.1.0
*/
@Getter
+@Setter
public class UserRegisterVO {
@NotBlank(message = "用户名不能为空")
- @Pattern(regexp = "^[\\u4e00-\\u9fa5]{2,5}$", message = "用户名只能为字母、数字或下划线")
+ @Pattern(regexp = "^[0-9A-Za-z_]{3,40}$", message = "用户名只能为字母、数字或下划线")
private String username;
@NotBlank(message = "密码不能为空")
private String password;
- @Pattern(regexp = "^[012]$", message = "保密:0,男:1,女:2")
+ @NotBlank(message = "家乡不能为空")
+ private String address;
+
+ @NotBlank(message = "电话不能为空")
+ @Pattern(regexp = "^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\\d{8}$", message = "电话格式错误")
+ private String phone;
+
+ @NotBlank(message = "邮箱不能为空")
+ @Pattern(regexp = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$", message = "邮箱格式错误")
+ private String email;
+
+ @Min(value = 0, message = "保密:0,男:1,女:2")
+ @Max(value = 2, message = "保密:0,男:1,女:2")
+ @NotNull(message = "性别不能为空")
private Short sex;
- @NotBlank(message = "年龄不能为空")
+ @NotNull(message = "年龄不能为空")
private Short age;
-
- @NotBlank(message = "单位不能为空")
- private String unit;
-
- @NotBlank(message = "职位/专业不能为空")
- private String filed;
-
- @NotBlank(message = "家乡不能为空")
- private String hometown;
}
diff --git a/src/main/java/com/jsl/oa/model/voData/UserReturnBackVO.java b/src/main/java/com/jsl/oa/model/voData/UserReturnBackVO.java
new file mode 100644
index 0000000..55aaf1e
--- /dev/null
+++ b/src/main/java/com/jsl/oa/model/voData/UserReturnBackVO.java
@@ -0,0 +1,28 @@
+package com.jsl.oa.model.voData;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+/**
+ * 用户注册成功UserDO自定义实体类
+ *
+ * 用于处理用户注册表单输出的数据
+ *
+ * @author 筱锋xiao_lfeng
+ * @version v1.1.0
+ * @since v1.1.0
+ */
+@Getter
+@Setter
+@Accessors(chain = true)
+public class UserReturnBackVO {
+ private String jobId;
+ private String username;
+ private String address;
+ private String phone;
+ private String email;
+ private Short age;
+ private Short sex;
+ private String token;
+}
diff --git a/src/main/java/com/jsl/oa/services/AuthService.java b/src/main/java/com/jsl/oa/services/AuthService.java
index f9a9132..6b4fb1c 100644
--- a/src/main/java/com/jsl/oa/services/AuthService.java
+++ b/src/main/java/com/jsl/oa/services/AuthService.java
@@ -4,9 +4,45 @@ import com.jsl.oa.model.voData.UserLoginVO;
import com.jsl.oa.model.voData.UserRegisterVO;
import com.jsl.oa.utils.BaseResponse;
-import java.text.ParseException;
-
+/**
+ * 用户认证服务接口
+ *
+ * 用户认证服务接口,包含用户注册、用户登录、用户登出接口
+ *
+ * @version v1.1.0
+ * @since v1.0.0
+ */
public interface AuthService {
- BaseResponse authRegister(UserRegisterVO userRegisterVO) throws ParseException;
+ /**
+ * 用户注册
+ *
+ * 用户注册服务类操作
+ *
+ * @param userRegisterVO 用户注册信息
+ * @return {@link BaseResponse}
+ * @author 筱锋xiao_lfeng
+ */
+ BaseResponse authRegister(UserRegisterVO userRegisterVO);
+
+ /**
+ * 用户登录
+ *
+ * 用户登录服务类操作
+ *
+ * @param userLoginVO 用户登录信息
+ * @return {@link BaseResponse}
+ * @author 176yunxuan
+ */
BaseResponse authLogin(UserLoginVO userLoginVO);
+
+ /**
+ * 用户登出
+ *
+ * 用户登出服务类操作
+ *
+ * @param email 用户邮箱
+ * @return {@link BaseResponse}
+ * @author 筱锋xiao_lfeng
+ */
+ BaseResponse authLoginByEmail(String email);
}
diff --git a/src/main/java/com/jsl/oa/services/MailService.java b/src/main/java/com/jsl/oa/services/MailService.java
new file mode 100644
index 0000000..36e8153
--- /dev/null
+++ b/src/main/java/com/jsl/oa/services/MailService.java
@@ -0,0 +1,8 @@
+package com.jsl.oa.services;
+
+import javax.mail.MessagingException;
+
+public interface MailService {
+ void sendMail() throws MessagingException;
+}
+
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 a282f0b..7f44354 100644
--- a/src/main/java/com/jsl/oa/services/impl/AuthServiceImpl.java
+++ b/src/main/java/com/jsl/oa/services/impl/AuthServiceImpl.java
@@ -2,57 +2,55 @@ package com.jsl.oa.services.impl;
import com.jsl.oa.model.doData.UserDO;
import com.jsl.oa.model.voData.UserLoginVO;
+import com.jsl.oa.model.voData.UserReturnBackVO;
import com.jsl.oa.model.voData.UserRegisterVO;
import com.jsl.oa.exception.BusinessException;
import com.jsl.oa.mapper.UserMapper;
import com.jsl.oa.services.AuthService;
-import com.jsl.oa.utils.BaseResponse;
-import com.jsl.oa.utils.ErrorCode;
-import com.jsl.oa.utils.Processing;
-import com.jsl.oa.utils.ResultUtil;
+import com.jsl.oa.utils.*;
import lombok.RequiredArgsConstructor;
+import org.jetbrains.annotations.NotNull;
import org.mindrot.jbcrypt.BCrypt;
import org.springframework.stereotype.Service;
-import java.text.ParseException;
-
+/**
+ * 用户认证服务实现类
+ *
+ * 用户认证服务实现类,包含用户注册、用户登录、用户登出接口
+ *
+ * @since v1.0.0
+ * @version v1.1.0
+ * @see AuthService
+ */
@Service
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {
private final UserMapper userMapper;
- /**
- * 用户注册
- *
- * 用户注册服务类操作
- *
- * @param userRegisterVO 用户注册信息
- * @return {@link BaseResponse}
- * @throws ParseException 日期转换异常
- */
@Override
public BaseResponse authRegister(UserRegisterVO userRegisterVO) {
- // 用户检查是否存在
+ // 检查用户说是否存在
UserDO getUserByUsername = userMapper.getUserInfoByUsername(userRegisterVO.getUsername());
// 用户名已存在
if (getUserByUsername != null) {
return ResultUtil.error(ErrorCode.USER_EXIST);
}
-
// 生成工号
String userNum;
do {
userNum = Processing.createJobNumber((short) 2);
} while (userMapper.getUserByUserNum(userNum) != null);
- // 处理性别
// 数据上传
UserDO userDO = new UserDO();
userDO.setJobId(userNum)
.setUsername(userRegisterVO.getUsername())
.setPassword(BCrypt.hashpw(userRegisterVO.getPassword(), BCrypt.gensalt()))
- .setSex(userRegisterVO.getSex())
- .setAge(userRegisterVO.getAge());
+ .setAddress(userRegisterVO.getAddress())
+ .setPhone(userRegisterVO.getPhone())
+ .setEmail(userRegisterVO.getEmail())
+ .setAge(userRegisterVO.getAge())
+ .setSex(userRegisterVO.getSex());
// 插入数据
if (userMapper.insertUser(userDO)) {
userDO.setPassword(null);
@@ -63,15 +61,31 @@ public class AuthServiceImpl implements AuthService {
}
@Override
- public BaseResponse authLogin(UserLoginVO userLoginVO) {
- String pwd = userLoginVO.getPassword();
- String encodePwd = userMapper.loginPassword(userLoginVO);
- if (encodePwd == null) {
+ public BaseResponse authLogin(@NotNull UserLoginVO userLoginVO) {
+ // 检查用户是否存在
+ UserDO userDO = userMapper.getUserInfoByUsername(userLoginVO.getUser());
+ if (userDO != null) {
+ // 获取用户并登陆
+ if (BCrypt.checkpw(userLoginVO.getPassword(), userDO.getPassword())) {
+ UserReturnBackVO userReturnBackVO = new UserReturnBackVO();
+ // 授权 Token
+ String token = JwtUtil.generateToken(userDO.getUsername());
+ 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);
+ } else {
+ return ResultUtil.error(ErrorCode.WRONG_PASSWORD);
+ }
+ } else {
return ResultUtil.error(ErrorCode.USER_NOT_EXIST);
}
- if (BCrypt.checkpw(pwd, encodePwd)) {
- return ResultUtil.success("登陆成功", userMapper.login(userLoginVO));
- } else return ResultUtil.error(ErrorCode.WRONG_PASSWORD);
+ }
}
}
diff --git a/src/main/java/com/jsl/oa/services/impl/MailServiceImpl.java b/src/main/java/com/jsl/oa/services/impl/MailServiceImpl.java
new file mode 100644
index 0000000..51b5515
--- /dev/null
+++ b/src/main/java/com/jsl/oa/services/impl/MailServiceImpl.java
@@ -0,0 +1,47 @@
+package com.jsl.oa.services.impl;
+
+import com.jsl.oa.services.MailService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.MimeMessageHelper;
+import org.springframework.stereotype.Service;
+
+import javax.mail.internet.MimeMessage;
+
+@Service
+@RequiredArgsConstructor
+public class MailServiceImpl implements MailService {
+ private final JavaMailSender javaMailSender;
+
+ @Value("${spring.mail.username}")
+ private String from;
+
+
+ @Override
+ public void sendMail() {
+ //发送多媒体邮件
+ try {
+ MimeMessage message = javaMailSender.createMimeMessage();
+
+ //第二个参数控制着附件上传
+ MimeMessageHelper helper = new MimeMessageHelper(message, true);
+
+ helper.setFrom(from);
+ String to = "lfengzeng@vip.qq.com";
+ helper.setTo(to);
+ String subject = "springboot测试邮件";
+ helper.setSubject(subject);
+
+ //第二个参数表示以 html 语法解析文本
+ String text = "你好:这是一封测试邮件。请坚持下去。加油!";
+ helper.setText(text, true);
+
+ javaMailSender.send(message);
+
+ } catch (Exception e) {
+ //TODO: 10001-发送邮件失败处理
+ }
+
+ }
+}
diff --git a/src/main/java/com/jsl/oa/utils/ErrorCode.java b/src/main/java/com/jsl/oa/utils/ErrorCode.java
index 02b5895..a13ea59 100644
--- a/src/main/java/com/jsl/oa/utils/ErrorCode.java
+++ b/src/main/java/com/jsl/oa/utils/ErrorCode.java
@@ -10,6 +10,7 @@ public enum ErrorCode {
USER_EXIST("UserExist", 40013, "用户名已存在"),
TIMESTAMP_ERROR("TimestampError", 40014, "时间戳错误"),
USER_NOT_EXIST("UserNotExist", 40015, "用户不存在"),
+ UNAUTHORIZED("Unauthorized", 40100, "未授权"),
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 adf9801..464d04a 100644
--- a/src/main/java/com/jsl/oa/utils/JwtUtil.java
+++ b/src/main/java/com/jsl/oa/utils/JwtUtil.java
@@ -7,10 +7,11 @@ import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
+import java.util.regex.Pattern;
public class JwtUtil {
// 替换为实际的密钥,建议使用足够长的随机字符串
- private static final String SECRET_KEY = Processing.createJobNumber((short) 1, (short) 255);
+ private static final String SECRET_KEY = "238542310128901753637022851772455105464283332917211091531086967815273100806759714250034263888525489008903447113697698540563820710887668094087054975808574632265678643370464260078072153369247242449569221118098938297741582538222826493707667477115117609126233";
// Token 有效期,这里设置为一天,可以根据实际需求调整
private static final long EXPIRATION_TIME = 86400000;
@@ -27,7 +28,7 @@ public class JwtUtil {
}
// 验证Token
- public static boolean verify(String token, String username) {
+ public static boolean verify(String token) {
try {
Key key = Keys.hmacShaKeyFor(SECRET_KEY.getBytes());
@@ -38,9 +39,8 @@ public class JwtUtil {
// 从JWT中获取用户名进行匹配
String tokenUsername = claimsJws.getBody().getSubject();
-
// 验证用户名是否匹配
- return username.equals(tokenUsername);
+ return Pattern.matches("^[0-9A-Za-z_]{3,40}$", tokenUsername);
} catch (Exception e) {
// 验证失败
return false;
diff --git a/src/main/java/com/jsl/oa/utils/Processing.java b/src/main/java/com/jsl/oa/utils/Processing.java
index 74df2ea..a90dc8b 100644
--- a/src/main/java/com/jsl/oa/utils/Processing.java
+++ b/src/main/java/com/jsl/oa/utils/Processing.java
@@ -1,5 +1,6 @@
package com.jsl.oa.utils;
+import org.jetbrains.annotations.NotNull;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
@@ -25,7 +26,7 @@ public class Processing {
* @param bindingResult 参数校验结果
* @return {@link ArrayList}
*/
- public static ArrayList getValidatedErrorList(BindingResult bindingResult) {
+ public static @NotNull ArrayList getValidatedErrorList(BindingResult bindingResult) {
ArrayList arrayList = new ArrayList<>();
for (ObjectError objectError : bindingResult.getAllErrors()) {
arrayList.add(objectError.getDefaultMessage());
@@ -42,7 +43,7 @@ public class Processing {
* @param type 0:学生 1:教师 2:其他
* @return {@link String}
*/
- public static String createJobNumber(Short type) {
+ public static @NotNull String createJobNumber(Short type) {
return createJobNumber(type, (short) 10);
}
@@ -56,7 +57,7 @@ public class Processing {
* @param size 工号长度
* @return {@link String}
*/
- public static String createJobNumber(Short type, Short size) {
+ public static @NotNull String createJobNumber(Short type, Short size) {
StringBuilder stringBuilder = new StringBuilder();
if (type == 0) {
stringBuilder.append("STU");
@@ -72,4 +73,17 @@ public class Processing {
}
return stringBuilder.toString();
}
+
+ /**
+ *
+ */
+ public static @NotNull String createCode() {
+ StringBuilder stringBuilder = new StringBuilder();
+ // 生成验证码
+ Random random = new Random();
+ for (int i = 0; i < 6; i++) {
+ stringBuilder.append(random.nextInt(10));
+ }
+ return stringBuilder.toString();
+ }
}
diff --git a/src/main/resources/.gitkeep b/src/main/resources/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 4f965f8..f200532 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -8,6 +8,8 @@ spring:
database: 0
host: localhost
port: 6379
+ profiles:
+ active: dev
mybatis:
configuration:
map-underscore-to-camel-case: true
diff --git a/src/test/java/com/jsl/oa/JslOrganizeInternalOaApplicationTests.java b/src/test/java/com/jsl/oa/JslOrganizeInternalOaApplicationTests.java
index 96601ad..23d7f62 100644
--- a/src/test/java/com/jsl/oa/JslOrganizeInternalOaApplicationTests.java
+++ b/src/test/java/com/jsl/oa/JslOrganizeInternalOaApplicationTests.java
@@ -10,7 +10,7 @@ class JslOrganizeInternalOaApplicationTests {
@Test
void contextLoads() {
String token = JwtUtil.generateToken("admin");
- if (JwtUtil.verify(token, "admin")) {
+ if (JwtUtil.verify(token)) {
System.out.println("验证通过");
} else {
System.out.println("验证失败");