配置安全模块与邮件登陆模组

This commit is contained in:
筱锋xiao_lfeng 2024-01-15 21:38:40 +08:00
parent e6d88afd79
commit 45c0ad0da0
No known key found for this signature in database
GPG Key ID: F693AA12AABBFA87
30 changed files with 467 additions and 190 deletions

1
.gitignore vendored
View File

@ -34,3 +34,4 @@ build/
### 自定义 ###
*.pdf
/src/main/resources/application-dev.yml

View File

@ -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 '更新时间'

16
pom.xml
View File

@ -103,6 +103,22 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>24.1.0</version>
<scope>compile</scope>
</dependency>
<!-- SpringBoot Mail -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- Gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
</dependencies>
<build>

View File

@ -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;
/**
* <h1>JWT过滤器</h1>
* <hr/>
* 用于JWT的过滤器
*
* @since v1.1.0
* @version v1.1.0
* @author 筱锋xiao_lfeng
*/
public class JwtFilter extends BasicHttpAuthenticationFilter {
/**
* <h2>判断用户Token</h2>
* <hr/>
* 判断用户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);
}
}
/**
* <h2>访问被拒绝时</h2>
* <hr/>
* 当访问被拒绝时会调用此方法
*
* @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;
}
/**
* <h2>获取Authorization Header</h2>
* <hr/>
* 用于获取Authorization Header
*
* @param request 请求
* @return {@link String}
*/
@Override
protected String getAuthzHeader(ServletRequest request) {
HttpServletRequest httpRequest = (HttpServletRequest) request;
return httpRequest.getHeader("Authorization");
}
}

View File

@ -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;
}
}

View File

@ -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;
/**
* <h1>邮件配置类</h1>
* <hr/>
* 用于配置邮件发送相关信息
*
* @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;
}
}

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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<String, String> 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<String, Filter> filters = new LinkedHashMap<>();
filters.put("jwt", new JwtFilter()); // 配置自定义的JWT过滤器
shiroFilterFactoryBean.setFilters(filters);
return shiroFilterFactoryBean;
}

View File

@ -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;
/**
* <h1>用户认证控制器</h1>
* <hr/>
* 用户认证控制器包含用户注册用户登录用户登出接口
*
* @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 {
* <hr/>
* 用户注册接口
*
* @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 {
* <hr/>
* 用户登录接口
*
* @since v1.0.0
* @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);
}
/**
* <h2>用户邮箱登录</h2>
* <hr/>
* 用户邮箱登录接口
*
* @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);
}
}
/**
* <h2>用户登出</h2>
* <hr/>
* 用户登出接口
*
* @return {@link BaseResponse}
* @since v1.1.0
*/
@GetMapping("/auth/logout")
public BaseResponse authLogout() {
return null;
}

View File

@ -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系统服务器处于正常状态");

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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

View File

@ -13,6 +13,15 @@ public class UserDAO {
private final UserMapper userMapper;
/**
* <h2>用户名获取用户信息</h2>
* <hr/>
* 根据用户名获取用户信息
*
* @param username 用户名
* @author 筱锋xiao_lfeng
* @return {@link UserDO}
*/
public UserDO getUserInfoByUsername(String username) {
UserDO userDO = null;
// Redis 获取数据

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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.*;
/**
* <h1>用户注册自定义实体类</h1>
@ -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;
}

View File

@ -0,0 +1,28 @@
package com.jsl.oa.model.voData;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
/**
* <h1>用户注册成功UserDO自定义实体类</h1>
* <hr/>
* 用于处理用户注册表单输出的数据
*
* @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;
}

View File

@ -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;
/**
* <h1>用户认证服务接口</h1>
* <hr/>
* 用户认证服务接口包含用户注册用户登录用户登出接口
*
* @version v1.1.0
* @since v1.0.0
*/
public interface AuthService {
BaseResponse authRegister(UserRegisterVO userRegisterVO) throws ParseException;
/**
* <h2>用户注册</h2>
* <hr/>
* 用户注册服务类操作
*
* @param userRegisterVO 用户注册信息
* @return {@link BaseResponse}
* @author 筱锋xiao_lfeng
*/
BaseResponse authRegister(UserRegisterVO userRegisterVO);
/**
* <h2>用户登录</h2>
* <hr/>
* 用户登录服务类操作
*
* @param userLoginVO 用户登录信息
* @return {@link BaseResponse}
* @author 176yunxuan
*/
BaseResponse authLogin(UserLoginVO userLoginVO);
/**
* <h2>用户登出</h2>
* <hr/>
* 用户登出服务类操作
*
* @param email 用户邮箱
* @return {@link BaseResponse}
* @author 筱锋xiao_lfeng
*/
BaseResponse authLoginByEmail(String email);
}

View File

@ -0,0 +1,8 @@
package com.jsl.oa.services;
import javax.mail.MessagingException;
public interface MailService {
void sendMail() throws MessagingException;
}

View File

@ -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;
/**
* <h1>用户认证服务实现类</h1>
* <hr/>
* 用户认证服务实现类包含用户注册用户登录用户登出接口
*
* @since v1.0.0
* @version v1.1.0
* @see AuthService
*/
@Service
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {
private final UserMapper userMapper;
/**
* <h1>用户注册</h1>
* <hr/>
* 用户注册服务类操作
*
* @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);
}
}
}

View File

@ -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-发送邮件失败处理
}
}
}

View File

@ -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, "数据库删除错误");

View File

@ -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;

View File

@ -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<String>}
*/
public static ArrayList<String> getValidatedErrorList(BindingResult bindingResult) {
public static @NotNull ArrayList<String> getValidatedErrorList(BindingResult bindingResult) {
ArrayList<String> 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();
}
}

View File

View File

@ -8,6 +8,8 @@ spring:
database: 0
host: localhost
port: 6379
profiles:
active: dev
mybatis:
configuration:
map-underscore-to-camel-case: true

View File

@ -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("验证失败");