feat(新增): UserFactory未完成
This commit is contained in:
parent
988790fea1
commit
8fae01c4a2
|
@ -27,7 +27,7 @@ class AdminGenerator {
|
|||
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
generation("sys_user")
|
||||
generation("sys_email_template")
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -50,6 +50,8 @@ class RedisConfiguration {
|
|||
redisTemplate.hashKeySerializer = StringRedisSerializer()
|
||||
redisTemplate.hashValueSerializer = GenericJackson2JsonRedisSerializer()
|
||||
|
||||
// 开启Redis事务
|
||||
redisTemplate.setEnableTransactionSupport(true)
|
||||
return redisTemplate
|
||||
}
|
||||
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
package cn.bunny.common.service.config
|
||||
|
||||
import cn.bunny.common.service.interceptor.UserTokenInterceptor
|
||||
import lombok.extern.slf4j.Slf4j
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
|
||||
|
||||
@Configuration
|
||||
@Slf4j
|
||||
open class WebMvcConfiguration : WebMvcConfigurer {
|
||||
@Autowired
|
||||
private val userTokenInterceptor: UserTokenInterceptor? = null
|
||||
|
||||
/**
|
||||
* 跨域配置
|
||||
*
|
||||
* @param registry 跨域注册表
|
||||
*/
|
||||
override fun addCorsMappings(registry: CorsRegistry) {
|
||||
registry.addMapping("/**") // 是否发送Cookies
|
||||
.allowCredentials(true) // 放行哪些原始域
|
||||
.allowedOriginPatterns("*").allowedMethods("GET", "POST", "PUT", "DELETE").allowedHeaders("*")
|
||||
.exposedHeaders("*")
|
||||
}
|
||||
|
||||
override fun addInterceptors(registry: InterceptorRegistry) {
|
||||
// TODO Spring Security 和这个拦截器任选一个
|
||||
val excludeList = arrayOf(
|
||||
"/", "/test/**", "/*.html", "/*/*/noAuth/**", "/*/noAuth/**", "/favicon.ico",
|
||||
"/swagger-resources/**", "/swagger-ui.html/**", "/admin/login", "/v3/**", "/api/**"
|
||||
)
|
||||
registry.addInterceptor(userTokenInterceptor!!).excludePathPatterns(*excludeList)
|
||||
|
||||
// TODO 如果想使用普通JWT可以使用这个,不使用 SpringSecurity6
|
||||
// registry.addInterceptor(userTokenInterceptor).addPathPatterns("/api/**").excludePathPatterns(excludeList);
|
||||
}
|
||||
}
|
|
@ -36,7 +36,7 @@ class GlobalExceptionHandler {
|
|||
fun exceptionHandler(exception: RuntimeException): Result<Any?> {
|
||||
logger.error("GlobalExceptionHandler===>运行时异常信息:{}", exception.message)
|
||||
exception.printStackTrace()
|
||||
return Result.error(null, 500, "出错了啦")
|
||||
return Result.error(null, 500, "出错了")
|
||||
}
|
||||
|
||||
// 捕获系统异常
|
||||
|
@ -47,12 +47,19 @@ class GlobalExceptionHandler {
|
|||
|
||||
// 错误消息
|
||||
val message = exception.message ?: ""
|
||||
|
||||
// 匹配到内容
|
||||
val patternString = "Request method '(\\w+)' is not supported"
|
||||
val matcher = Pattern.compile(patternString).matcher(message)
|
||||
|
||||
// 请求API不存在
|
||||
val noStaticResource = "No static resource (.*)\\."
|
||||
val noStaticResourceMatcher = Pattern.compile(noStaticResource).matcher(message)
|
||||
if (noStaticResourceMatcher.find()) return Result.error(null, 500, "请求API不存在 " + noStaticResourceMatcher.group(1))
|
||||
|
||||
return when {
|
||||
matcher.find() -> Result.error(null, 500, "请求方法错误,不是 " + matcher.group(1))
|
||||
noStaticResourceMatcher.find() -> return Result.error(null, 500, "请求API不存在 " + noStaticResourceMatcher.group(1))
|
||||
else -> Result.error(null, 500, "系统异常")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
package cn.bunny.common.service.utils
|
||||
|
||||
import cn.bunny.common.service.exception.BunnyException
|
||||
import jakarta.annotation.PostConstruct
|
||||
import lombok.extern.slf4j.Slf4j
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.lionsoul.ip2region.xdb.Searcher
|
||||
import org.springframework.core.io.ClassPathResource
|
||||
import org.springframework.util.FileCopyUtils
|
||||
import java.util.regex.Pattern
|
||||
|
||||
@Slf4j
|
||||
class IpUtil {
|
||||
|
||||
companion object {
|
||||
private val logger = LogManager.getLogger(IpUtil::class.java)
|
||||
private var searcher: Searcher? = null
|
||||
|
||||
/**
|
||||
* 判断是否为合法 IP
|
||||
*/
|
||||
private fun checkIp(ipAddress: String): Boolean {
|
||||
val ip = "([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}"
|
||||
val pattern = Pattern.compile(ip)
|
||||
val matcher = pattern.matcher(ipAddress)
|
||||
|
||||
return matcher.matches()
|
||||
}
|
||||
|
||||
/**
|
||||
* 在服务启动时,将 ip2region 加载到内存中
|
||||
*/
|
||||
@PostConstruct
|
||||
private fun initIp2Region() {
|
||||
try {
|
||||
val inputStream = ClassPathResource("/ipdb/ip2region.xdb").inputStream
|
||||
val bytes = FileCopyUtils.copyToByteArray(inputStream)
|
||||
searcher = Searcher.newWithBuffer(bytes)
|
||||
} catch (exception: Exception) {
|
||||
logger.error(exception.message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 ip 所属地址
|
||||
*
|
||||
* @param checkIp ip
|
||||
*/
|
||||
fun getIpRegion(checkIp: String): String {
|
||||
val ip = if (checkIp == "0:0:0:0:0:0:0:1") "127.0.0.1" else checkIp
|
||||
if (!checkIp(ip)) throw BunnyException("非法的IP地址")
|
||||
|
||||
val searchIpInfo = searcher?.search(ip)
|
||||
return searchIpInfo?.let { it ->
|
||||
val splitIpInfo = it.split("\\|".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
if (splitIpInfo.isNotEmpty()) {
|
||||
when {
|
||||
splitIpInfo[0] == "中国" -> splitIpInfo[2] // 国内属地返回省份
|
||||
splitIpInfo[0] == "0" && splitIpInfo[4] == "内网IP" -> splitIpInfo[4] // 内网 IP
|
||||
else -> splitIpInfo[0] // 国外属地返回国家
|
||||
}
|
||||
} else ""
|
||||
} ?: ""
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,17 +44,23 @@ class MailSenderUtil(emailSendInit: EmailSendInit) {
|
|||
|
||||
// 设置发送人
|
||||
helper.setFrom(username!!)
|
||||
|
||||
// 设置邮件接受者
|
||||
helper.setTo(emailSend.sendTo!!)
|
||||
|
||||
// 设置邮件主题
|
||||
helper.setSubject(emailSend.subject!!)
|
||||
|
||||
// 设置发送消息 为富文本
|
||||
helper.setText(emailSend.message!!, emailSend.isRichText!!)
|
||||
helper.setText(emailSend.message!!, emailSend.isRichText)
|
||||
|
||||
// 设置抄送人
|
||||
helper.setCc(emailSend.ccParam!!.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray())
|
||||
val split: List<String> = emailSend.ccParam?.split(",") ?: emptyList()
|
||||
helper.setCc(split.toTypedArray())
|
||||
|
||||
// 邮件添加附件
|
||||
val files = emailSend.file
|
||||
for (file in files!!) {
|
||||
val files = emailSend.files
|
||||
if (files !== null) for (file in files) {
|
||||
helper.addAttachment(Objects.requireNonNull(file.originalFilename), file)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package cn.bunny.common.service.utils.ip
|
||||
|
||||
import io.swagger.annotations.ApiModel
|
||||
import io.swagger.annotations.ApiModelProperty
|
||||
import lombok.AllArgsConstructor
|
||||
import lombok.Builder
|
||||
import lombok.Data
|
||||
import lombok.NoArgsConstructor
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@ApiModel(value = "IpEntity对象", description = "用户IP相关信息")
|
||||
class IpEntity {
|
||||
@ApiModelProperty("原始地址")
|
||||
var remoteAddr: String? = null
|
||||
|
||||
@ApiModelProperty("IP归属地")
|
||||
var ipRegion: String? = null
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package cn.bunny.common.service.utils.ip
|
||||
|
||||
import jakarta.annotation.PostConstruct
|
||||
import lombok.extern.slf4j.Slf4j
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.lionsoul.ip2region.xdb.Searcher
|
||||
import org.springframework.core.io.ClassPathResource
|
||||
import org.springframework.util.FileCopyUtils
|
||||
import org.springframework.web.context.request.RequestContextHolder
|
||||
import org.springframework.web.context.request.ServletRequestAttributes
|
||||
import java.util.regex.Pattern
|
||||
|
||||
@Slf4j
|
||||
class IpUtil {
|
||||
|
||||
companion object {
|
||||
private val logger = LogManager.getLogger(IpUtil::class.java)
|
||||
private var searcher: Searcher? = null
|
||||
|
||||
/**
|
||||
* 判断是否为合法 IP
|
||||
*/
|
||||
fun checkIp(ipAddress: String): Boolean {
|
||||
val ip = "([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}"
|
||||
val pattern = Pattern.compile(ip)
|
||||
val matcher = pattern.matcher(ipAddress)
|
||||
|
||||
return matcher.matches()
|
||||
}
|
||||
|
||||
/**
|
||||
* 在服务启动时,将 ip2region 加载到内存中
|
||||
*/
|
||||
@PostConstruct
|
||||
fun initIp2Region() {
|
||||
try {
|
||||
val inputStream = ClassPathResource("/ipdb/ip2region.xdb").inputStream
|
||||
val bytes = FileCopyUtils.copyToByteArray(inputStream)
|
||||
searcher = Searcher.newWithBuffer(bytes)
|
||||
} catch (exception: Exception) {
|
||||
logger.error(exception.message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 ip 所属地址
|
||||
*
|
||||
* @param ip ip
|
||||
*/
|
||||
private fun getIpRegion(ip: String): String {
|
||||
var checkIp = ip
|
||||
if (checkIp == "0:0:0:0:0:0:0:1") checkIp = "127.0.0.1"
|
||||
val isIp = checkIp(checkIp)
|
||||
if (isIp) {
|
||||
initIp2Region()
|
||||
try {
|
||||
// searchIpInfo 的数据格式: 国家|区域|省份|城市|ISP
|
||||
val searchIpInfo: String = searcher!!.search(checkIp)
|
||||
val splitIpInfo = searchIpInfo.split("\\|".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
if (splitIpInfo.isNotEmpty()) {
|
||||
return if ("中国" == splitIpInfo[0]) {
|
||||
// 国内属地返回省份
|
||||
splitIpInfo[2]
|
||||
} else if ("0" == splitIpInfo[0]) {
|
||||
if ("内网IP" == splitIpInfo[4]) splitIpInfo[4] else ""
|
||||
} else splitIpInfo[0]
|
||||
}
|
||||
} catch (exception: java.lang.Exception) {
|
||||
logger.error("获取 ip 所属地址消息:{}", exception.message)
|
||||
logger.error("获取 ip 所属地址:{}", exception.stackTrace as Any)
|
||||
}
|
||||
return ""
|
||||
} else {
|
||||
throw IllegalArgumentException("非法的IP地址")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* * 获取当前用户登录IP地址
|
||||
*
|
||||
* @return IP地址
|
||||
*/
|
||||
fun getCurrentUserIpAddress(): IpEntity {
|
||||
// 获取用户IP地址
|
||||
val requestAttributes = RequestContextHolder.getRequestAttributes() as ServletRequestAttributes
|
||||
var remoteAddr = requestAttributes.request.remoteAddr
|
||||
val ipRegion = getIpRegion(remoteAddr)
|
||||
|
||||
// 设置返回对象
|
||||
val ipEntity = IpEntity()
|
||||
if (remoteAddr == "0:0:0:0:0:0:0:1") remoteAddr = "127.0.0.1"
|
||||
ipEntity.remoteAddr = remoteAddr
|
||||
ipEntity.ipRegion = ipRegion
|
||||
|
||||
return ipEntity
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.dao.dto.user
|
||||
package cn.bunny.dao.dto.system
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema
|
||||
import jakarta.validation.constraints.NotBlank
|
||||
|
@ -6,11 +6,13 @@ import lombok.AllArgsConstructor
|
|||
import lombok.Builder
|
||||
import lombok.Data
|
||||
import lombok.NoArgsConstructor
|
||||
import lombok.experimental.Accessors
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@Accessors(chain = true)
|
||||
@Schema(name = "LoginDto", title = "登录表单内容", description = "登录表单内容")
|
||||
class LoginDto {
|
||||
@Schema(name = "username", title = "用户名")
|
||||
|
@ -21,4 +23,7 @@ class LoginDto {
|
|||
|
||||
@Schema(name = "emailCode", title = "邮箱验证码")
|
||||
var emailCode: @NotBlank(message = "邮箱验证码不能为空") String? = null
|
||||
|
||||
@Schema(name = "readMeDay", title = "记住我的天数")
|
||||
var readMeDay: Long = 7
|
||||
}
|
|
@ -4,13 +4,14 @@ import com.alibaba.fastjson2.annotation.JSONField
|
|||
import com.baomidou.mybatisplus.annotation.*
|
||||
import com.fasterxml.jackson.annotation.JsonFormat
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer
|
||||
import io.swagger.annotations.ApiModelProperty
|
||||
import io.swagger.v3.oas.annotations.media.Schema
|
||||
import lombok.Data
|
||||
import lombok.experimental.Accessors
|
||||
import java.io.Serializable
|
||||
import java.time.LocalDateTime
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(name = "BaseEntity", title = "基础实体类型", description = "基础实体类型")
|
||||
open class BaseEntity : Serializable {
|
||||
@Schema(name = "id", title = "唯一标识")
|
||||
|
@ -19,7 +20,6 @@ open class BaseEntity : Serializable {
|
|||
@JSONField(serializeUsing = ToStringSerializer::class)
|
||||
var id: Long? = null
|
||||
|
||||
@ApiModelProperty("创建时间")
|
||||
@Schema(name = "createTime", title = "创建时间")
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
var createTime: LocalDateTime? = null
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.dao.entity.user
|
||||
package cn.bunny.dao.entity.system
|
||||
|
||||
import cn.bunny.dao.entity.BaseEntity
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.dao.entity.email
|
||||
package cn.bunny.dao.entity.system
|
||||
|
||||
import cn.bunny.dao.entity.BaseEntity
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
||||
|
@ -10,19 +10,19 @@ import lombok.experimental.Accessors
|
|||
/**
|
||||
*
|
||||
*
|
||||
*
|
||||
* 邮件模板表
|
||||
*
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-05-19
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
@TableName("email_template")
|
||||
@Schema(name = "EmailTemplate", title = "邮件模板", description = "邮件模板")
|
||||
@TableName("sys_email_template")
|
||||
@Schema(name = "EmailTemplate对象", title = "邮件模板表", description = "邮件模板表")
|
||||
class EmailTemplate : BaseEntity() {
|
||||
@Schema(name = "templateName", title = "模板名称")
|
||||
@Schema(name = "email", title = "模板名称")
|
||||
var templateName: String? = null
|
||||
|
||||
@Schema(name = "subject", title = "主题")
|
||||
|
@ -33,4 +33,7 @@ class EmailTemplate : BaseEntity() {
|
|||
|
||||
@Schema(name = "type", title = "邮件类型")
|
||||
var type: String? = null
|
||||
|
||||
@Schema(name = "isDefault", title = "是否默认")
|
||||
var isDefault: Boolean? = null
|
||||
}
|
|
@ -1,10 +1,9 @@
|
|||
package cn.bunny.dao.entity.email
|
||||
package cn.bunny.dao.entity.system
|
||||
|
||||
import cn.bunny.dao.entity.BaseEntity
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
||||
import io.swagger.v3.oas.annotations.media.Schema
|
||||
import lombok.Getter
|
||||
import lombok.Setter
|
||||
import lombok.Data
|
||||
import lombok.experimental.Accessors
|
||||
|
||||
/**
|
||||
|
@ -14,17 +13,20 @@ import lombok.experimental.Accessors
|
|||
*
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-05-17
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@TableName("email_users")
|
||||
@TableName("sys_email_users")
|
||||
@Schema(name = "EmailUsers对象", title = "邮箱发送表", description = "邮箱发送表")
|
||||
class EmailUsers : BaseEntity() {
|
||||
open class EmailUsers : BaseEntity() {
|
||||
|
||||
@Schema(name = "email", title = "邮箱")
|
||||
var email: String? = null
|
||||
|
||||
@Schema(name = "emailTemplate", title = "使用邮件模板")
|
||||
var emailTemplate: Long? = null
|
||||
|
||||
@Schema(name = "password", title = "密码")
|
||||
var password: String? = null
|
||||
|
||||
|
@ -38,5 +40,5 @@ class EmailUsers : BaseEntity() {
|
|||
var smtpAgreement: String? = null
|
||||
|
||||
@Schema(name = "isDefault", title = "是否为默认邮件")
|
||||
var isDefault: Int? = null
|
||||
var isDefault: Byte? = null
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package cn.bunny.dao.entity.system;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统菜单图标
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
@TableName("sys_menu_icon")
|
||||
@ApiModel(value = "MenuIcon对象", description = "系统菜单图标")
|
||||
public class MenuIcon implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty("icon 名称")
|
||||
private String iconName;
|
||||
|
||||
@ApiModelProperty("创建用户")
|
||||
private Long createUser;
|
||||
|
||||
@ApiModelProperty("操作用户")
|
||||
private Long updateUser;
|
||||
|
||||
@ApiModelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@ApiModelProperty("更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@ApiModelProperty("是否删除")
|
||||
private Byte isDeleted;
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package cn.bunny.dao.entity.system;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统菜单表
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
@TableName("sys_router")
|
||||
@ApiModel(value = "Router对象", description = "系统菜单表")
|
||||
public class Router implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("主键id")
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty("在项目中路径")
|
||||
private String routerPath;
|
||||
|
||||
@ApiModelProperty("路由名称")
|
||||
private String routeName;
|
||||
|
||||
@ApiModelProperty("父级id")
|
||||
private Long parentId;
|
||||
|
||||
@ApiModelProperty("路由title")
|
||||
private String title;
|
||||
|
||||
@ApiModelProperty("图标")
|
||||
private String icon;
|
||||
|
||||
@ApiModelProperty("等级")
|
||||
private Integer routerRank;
|
||||
|
||||
@ApiModelProperty("是否显示")
|
||||
private Boolean visible;
|
||||
|
||||
@ApiModelProperty("创建用户")
|
||||
private Long createUser;
|
||||
|
||||
@ApiModelProperty("操作用户")
|
||||
private Long updateUser;
|
||||
|
||||
@ApiModelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@ApiModelProperty("更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@ApiModelProperty("是否删除")
|
||||
private Byte isDeleted;
|
||||
}
|
|
@ -24,7 +24,7 @@ class EmailSend {
|
|||
var subject: String? = null
|
||||
|
||||
@Schema(name = "isRichText", title = "是否为富文本")
|
||||
var isRichText: Boolean? = null
|
||||
var isRichText: Boolean = true
|
||||
|
||||
@Schema(name = "message", title = "发送内容")
|
||||
var message: String? = null
|
||||
|
@ -33,5 +33,5 @@ class EmailSend {
|
|||
var ccParam: String? = null
|
||||
|
||||
@Schema(name = "file", title = "发送的文件")
|
||||
var file: Array<MultipartFile>? = null
|
||||
var files: Array<MultipartFile>? = null
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package cn.bunny.dao.pojo.enums
|
||||
|
||||
enum class EmailTemplateTypes(val type: String, val summary: String) {
|
||||
VERIFICATION_CODE("verification_code", "邮箱验证码发送"),
|
||||
NOTIFICATION("notification", "通知型邮件"),
|
||||
WARNING("warning", "警告型邮件"),
|
||||
;
|
||||
}
|
|
@ -3,6 +3,6 @@ package cn.bunny.dao.pojo.enums
|
|||
/**
|
||||
* 数据库操作类型
|
||||
*/
|
||||
enum class OperationType {
|
||||
enum class OperationTypes {
|
||||
UPDATE, INSERT
|
||||
}
|
|
@ -15,15 +15,18 @@ enum class ResultCodeEnum(val code: Int, val message: String) {
|
|||
// 验证错误 201
|
||||
USERNAME_OR_PASSWORD_NOT_EMPTY(201, "用户名或密码不能为空"),
|
||||
EMAIL_CODE_NOT_EMPTY(201, "邮箱验证码不能为空"),
|
||||
SEND_EMAIL_CODE_NOT_EMPTY(201, "请先发送邮箱验证码"),
|
||||
EMAIL_CODE_EMPTY(201, "邮箱验证码过期或不存在"),
|
||||
EMAIL_CODE_NOT_MATCHING(201, "邮箱验证码不匹配"),
|
||||
LOGIN_ERROR(201, "账号或密码错误"),
|
||||
LOGIN_ERROR_USERNAME_PASSWORD_NOT_EMPTY(201, "登录信息不能为空"),
|
||||
SEND_MAIL_CODE_ERROR(201, "邮件发送失败"),
|
||||
|
||||
// 数据相关 206
|
||||
ILLEGAL_REQUEST(206, "非法请求"),
|
||||
REPEAT_SUBMIT(206, "重复提交"),
|
||||
DATA_ERROR(206, "数据异常"),
|
||||
EMAIL_TEMPLATE_IS_EMPTY(206, "邮件模板为空"),
|
||||
EMAIL_USER_TEMPLATE_IS_EMPTY(206, "邮件模板为空"),
|
||||
|
||||
// 身份过期 208
|
||||
LOGIN_AUTH(208, "请先登陆"),
|
||||
|
@ -31,7 +34,7 @@ enum class ResultCodeEnum(val code: Int, val message: String) {
|
|||
SESSION_EXPIRATION(208, "会话过期"),
|
||||
|
||||
// 封禁 209
|
||||
FAIL_NO_ACCESS_DENIED_USER_LOCKED(209, "该账户被封禁"),
|
||||
FAIL_NO_ACCESS_DENIED_USER_LOCKED(209, "账户已封禁"),
|
||||
THE_SAME_USER_HAS_LOGGED_IN(209, "相同用户已登录"),
|
||||
|
||||
// 提示错误
|
||||
|
|
|
@ -14,12 +14,12 @@ import lombok.*
|
|||
@Builder
|
||||
@Schema(name = "LoginVo对象", title = "登录成功返回内容", description = "登录成功返回内容")
|
||||
class LoginVo : BaseVo() {
|
||||
@Schema(name = "nickName", title = "昵称")
|
||||
var nickName: String? = null
|
||||
|
||||
@Schema(name = "username", title = "用户名")
|
||||
var username: String? = null
|
||||
|
||||
@Schema(name = "nickName", title = "昵称")
|
||||
var nickName: String? = null
|
||||
|
||||
@Schema(name = "email", title = "邮箱")
|
||||
var email: String? = null
|
||||
|
||||
|
@ -32,32 +32,20 @@ class LoginVo : BaseVo() {
|
|||
@Schema(name = "avatar", title = "头像")
|
||||
var avatar: String? = null
|
||||
|
||||
@Schema(name = "sex", title = "0:女 1:男")
|
||||
@Schema(name = "sex", title = "性别", description = "0:女 1:男")
|
||||
var sex: Byte? = null
|
||||
|
||||
@Schema(name = "personDescription", title = "个人描述")
|
||||
var personDescription: String? = null
|
||||
|
||||
@Schema(name = "articleMode", title = "文章显示模式")
|
||||
var articleMode: String? = null
|
||||
|
||||
@Schema(name = "layout", title = "页面布局方式")
|
||||
var layout: String? = null
|
||||
@Schema(name = "summary", title = "个人描述")
|
||||
var summary: String? = null
|
||||
|
||||
@Schema(name = "lastLoginIp", title = "最后登录IP")
|
||||
var lastLoginIp: String? = null
|
||||
|
||||
@Schema(name = "lastLoginIpAddress", title = "最后登录ip地址")
|
||||
@Schema(name = "lastLoginIpAddress", title = "最后登录ip归属地")
|
||||
var lastLoginIpAddress: String? = null
|
||||
|
||||
@Schema(name = "totalIntegral", title = "积分")
|
||||
var totalIntegral: Int? = null
|
||||
|
||||
@Schema(name = "currentIntegral", title = "当前积分")
|
||||
var currentIntegral: Int? = null
|
||||
|
||||
@Schema(name = "status", title = "0:禁用 1:正常")
|
||||
var status: Boolean? = null
|
||||
@Schema(name = "status", title = "状态", description = "1:禁用 0:正常")
|
||||
var status: Byte? = null
|
||||
|
||||
@Schema(name = "token", title = "令牌")
|
||||
var token: String? = null
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package cn.bunny.services.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 前端控制器
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/emailTemplate")
|
||||
public class EmailTemplateController {
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package cn.bunny.services.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 邮箱发送表 前端控制器
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/emailUsers")
|
||||
public class EmailUsersController {
|
||||
|
||||
}
|
|
@ -12,9 +12,9 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
@Tag(name = "多语言", description = "多语言相关接口")
|
||||
@RestController
|
||||
@RequestMapping("/i18n")
|
||||
@Tag(name = "多语言", description = "多语言相关接口")
|
||||
public class I18nController {
|
||||
|
||||
}
|
||||
|
|
|
@ -12,9 +12,9 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
@Tag(name = "多语言类型", description = "多语言类型相关接口")
|
||||
@RestController
|
||||
@RequestMapping("/i18nType")
|
||||
@Tag(name = "多语言类型", description = "多语言类型相关接口")
|
||||
public class I18nTypeController {
|
||||
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.RestController
|
|||
@RestController
|
||||
@RequestMapping("/")
|
||||
class IndexController {
|
||||
|
||||
@Operation(summary = "访问首页", description = "访问首页")
|
||||
@GetMapping("")
|
||||
fun index(): String {
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package cn.bunny.services.controller;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统菜单图标 前端控制器
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
@Tag(name = "菜单Icon", description = "菜单Icon相关接口")
|
||||
@RestController
|
||||
@RequestMapping("/menuIcon")
|
||||
public class MenuIconController {
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package cn.bunny.services.controller;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统菜单表 前端控制器
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
@Tag(name = "系统路由", description = "系统路由相关接口")
|
||||
@RestController
|
||||
@RequestMapping("/router")
|
||||
public class RouterController {
|
||||
|
||||
}
|
|
@ -1,6 +1,11 @@
|
|||
package cn.bunny.services.controller
|
||||
|
||||
import cn.bunny.dao.pojo.result.Result
|
||||
import cn.bunny.services.service.UserService
|
||||
import io.swagger.v3.oas.annotations.Operation
|
||||
import io.swagger.v3.oas.annotations.tags.Tag
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
|
@ -14,6 +19,17 @@ import org.springframework.web.bind.annotation.RestController
|
|||
* @since 2024-09-26
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/user")
|
||||
@RequestMapping("/admin/user")
|
||||
@Tag(name = "系统用户", description = "系统用户相关接口")
|
||||
class UserController
|
||||
class UserController {
|
||||
|
||||
@Autowired
|
||||
private lateinit var userService: UserService
|
||||
|
||||
@Operation(summary = "登录发送邮件验证码", description = "登录发送邮件验证码")
|
||||
@PostMapping("noAuth/sendLoginEmail")
|
||||
fun sendLoginEmail(email: String): Result<String> {
|
||||
userService.sendLoginEmail(email)
|
||||
return Result.success()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
package cn.bunny.services.factory
|
||||
|
||||
import cn.bunny.common.service.exception.BunnyException
|
||||
import cn.bunny.common.service.utils.email.MailSenderUtil
|
||||
import cn.bunny.dao.entity.system.EmailTemplate
|
||||
import cn.bunny.dao.pojo.email.EmailSend
|
||||
import cn.bunny.dao.pojo.email.EmailSendInit
|
||||
import cn.bunny.dao.pojo.enums.EmailTemplateTypes
|
||||
import cn.bunny.dao.pojo.result.ResultCodeEnum
|
||||
import cn.bunny.services.mapper.EmailTemplateMapper
|
||||
import cn.hutool.captcha.CaptchaUtil
|
||||
import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper
|
||||
import jakarta.mail.MessagingException
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
class EmailFactory {
|
||||
@Autowired
|
||||
private lateinit var emailTemplateMapper: EmailTemplateMapper
|
||||
|
||||
/**
|
||||
* * 生成邮箱验证码
|
||||
*
|
||||
* @param email 接受者邮箱
|
||||
* @param emailSendInit 初始化发送参数
|
||||
*/
|
||||
fun sendmailCode(email: String, emailSendInit: EmailSendInit): String {
|
||||
// 查询验证码邮件模板
|
||||
val lambdaQueryWrapper = KtQueryWrapper(EmailTemplate())
|
||||
lambdaQueryWrapper.eq(EmailTemplate::isDefault, 1)
|
||||
lambdaQueryWrapper.eq(EmailTemplate::type, EmailTemplateTypes.VERIFICATION_CODE.type)
|
||||
val emailTemplate = emailTemplateMapper.selectOne(lambdaQueryWrapper)
|
||||
|
||||
// 判断邮件模板是否为空
|
||||
if (emailTemplate === null) throw BunnyException(ResultCodeEnum.EMAIL_TEMPLATE_IS_EMPTY)
|
||||
|
||||
// 生成验证码
|
||||
val captcha = CaptchaUtil.createCircleCaptcha(150, 48, 4, 2)
|
||||
val code = captcha.code
|
||||
val htmlContent = emailTemplate.body?.replace("\${verifyCode}", code)
|
||||
|
||||
// 发送验证码
|
||||
val mailSenderUtil = MailSenderUtil(emailSendInit)
|
||||
try {
|
||||
val emailSend = EmailSend()
|
||||
emailSend.subject = emailTemplate.subject
|
||||
emailSend.message = htmlContent
|
||||
emailSend.sendTo = email
|
||||
emailSend.isRichText = true
|
||||
mailSenderUtil.sendEmail(emailSend)
|
||||
} catch (e: MessagingException) {
|
||||
throw BunnyException(ResultCodeEnum.SEND_MAIL_CODE_ERROR)
|
||||
}
|
||||
|
||||
return code
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package cn.bunny.services.factory
|
||||
|
||||
import cn.bunny.common.service.utils.JwtHelper
|
||||
import cn.bunny.common.service.utils.ip.IpUtil
|
||||
import cn.bunny.dao.entity.system.AdminUser
|
||||
import cn.bunny.dao.pojo.constant.RedisUserConstant.Companion.getAdminLoginInfoPrefix
|
||||
import cn.bunny.dao.pojo.constant.RedisUserConstant.Companion.getAdminUserEmailCodePrefix
|
||||
import cn.bunny.dao.vo.user.LoginVo
|
||||
import cn.bunny.services.mapper.UserMapper
|
||||
import org.springframework.beans.BeanUtils
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.beans.factory.annotation.Qualifier
|
||||
import org.springframework.data.redis.core.RedisTemplate
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@Component
|
||||
@Transactional
|
||||
class UserFactory {
|
||||
@Qualifier("redisTemplate")
|
||||
@Autowired
|
||||
private lateinit var redisTemplate: RedisTemplate<Any, Any>
|
||||
|
||||
@Autowired
|
||||
private lateinit var userMapper: UserMapper
|
||||
|
||||
fun buildUserVo(user: AdminUser, readMeDay: Long): LoginVo {
|
||||
// 创建token
|
||||
val userId = user.id
|
||||
val token = JwtHelper.createToken(userId, user.email, readMeDay.toInt())
|
||||
|
||||
// 设置用户IP地址,并更新用户信息
|
||||
val updateUser = AdminUser()
|
||||
updateUser.id = userId
|
||||
updateUser.lastLoginIp = IpUtil.getCurrentUserIpAddress().remoteAddr
|
||||
updateUser.lastLoginIpAddress = IpUtil.getCurrentUserIpAddress().ipRegion
|
||||
|
||||
// 构建返回对象
|
||||
val loginVo = LoginVo()
|
||||
BeanUtils.copyProperties(user, loginVo)
|
||||
loginVo.token = token
|
||||
loginVo.lastLoginIp = IpUtil.getCurrentUserIpAddress().remoteAddr
|
||||
loginVo.lastLoginIpAddress = IpUtil.getCurrentUserIpAddress().ipRegion
|
||||
// TODO 设置权限和角色内容
|
||||
loginVo.roleList = listOf("admin", "common")
|
||||
loginVo.powerList = listOf("*.*")
|
||||
|
||||
// 将信息保存在Redis中
|
||||
redisTemplate.opsForValue().set(getAdminLoginInfoPrefix(user.email!!), loginVo, readMeDay, TimeUnit.DAYS)
|
||||
|
||||
// 将Redis中验证码删除
|
||||
redisTemplate.delete(getAdminUserEmailCodePrefix(user.email!!))
|
||||
|
||||
return loginVo
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package cn.bunny.services.mapper;
|
||||
|
||||
import cn.bunny.dao.entity.system.EmailTemplate;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
@Mapper
|
||||
public interface EmailTemplateMapper extends BaseMapper<EmailTemplate> {
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package cn.bunny.services.mapper;
|
||||
|
||||
import cn.bunny.dao.entity.system.EmailUsers;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 邮箱发送表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
@Mapper
|
||||
public interface EmailUsersMapper extends BaseMapper<EmailUsers> {
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package cn.bunny.services.mapper;
|
||||
|
||||
import cn.bunny.dao.entity.system.MenuIcon;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统菜单图标 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
@Mapper
|
||||
public interface MenuIconMapper extends BaseMapper<MenuIcon> {
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package cn.bunny.services.mapper;
|
||||
|
||||
import cn.bunny.dao.entity.system.Router;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统菜单表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
@Mapper
|
||||
public interface RouterMapper extends BaseMapper<Router> {
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package cn.bunny.services.mapper;
|
||||
|
||||
import cn.bunny.dao.entity.user.AdminUser;
|
||||
import cn.bunny.dao.entity.system.AdminUser;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@ import cn.bunny.services.security.filter.TokenAuthenticationFilter
|
|||
import cn.bunny.services.security.filter.TokenLoginFilterService
|
||||
import cn.bunny.services.security.handelr.SecurityAccessDeniedHandler
|
||||
import cn.bunny.services.security.handelr.SecurityAuthenticationEntryPoint
|
||||
import cn.bunny.services.security.service.CustomAuthorizationManagerService
|
||||
import cn.bunny.services.security.service.CustomUserDetailsService
|
||||
import cn.bunny.services.security.service.impl.CustomAuthorizationManagerServiceImpl
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
|
@ -27,7 +27,7 @@ import org.springframework.security.web.util.matcher.RegexRequestMatcher
|
|||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableMethodSecurity
|
||||
open class WebSecurityConfig {
|
||||
class WebSecurityConfig {
|
||||
@Autowired
|
||||
private val redisTemplate: RedisTemplate<Any, Any>? = null
|
||||
|
||||
|
@ -41,14 +41,14 @@ open class WebSecurityConfig {
|
|||
|
||||
// 自定义验证码
|
||||
@Autowired
|
||||
private val customAuthorizationManager: CustomAuthorizationManagerService? = null
|
||||
private val customAuthorizationManager: CustomAuthorizationManagerServiceImpl? = null
|
||||
|
||||
@Autowired
|
||||
private val authenticationConfiguration: AuthenticationConfiguration? = null
|
||||
|
||||
@Bean
|
||||
@Throws(Exception::class)
|
||||
open fun filterChain(httpSecurity: HttpSecurity): SecurityFilterChain {
|
||||
fun filterChain(httpSecurity: HttpSecurity): SecurityFilterChain {
|
||||
httpSecurity // 前端段分离不需要---禁用明文验证
|
||||
.httpBasic { obj: HttpBasicConfigurer<HttpSecurity> -> obj.disable() } // 前端段分离不需要---禁用默认登录页
|
||||
.formLogin { obj: FormLoginConfigurer<HttpSecurity> -> obj.disable() } // 前端段分离不需要---禁用退出页
|
||||
|
@ -90,7 +90,7 @@ open class WebSecurityConfig {
|
|||
|
||||
// 排出鉴定路径
|
||||
@Bean
|
||||
open fun webSecurityCustomizer(): WebSecurityCustomizer {
|
||||
fun webSecurityCustomizer(): WebSecurityCustomizer {
|
||||
val annotations = arrayOf(
|
||||
"/", "/ws/**",
|
||||
"/*/*/noAuth/**", "/*/noAuth/**", "/noAuth/**",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package cn.bunny.services.security.custom
|
||||
|
||||
import cn.bunny.dao.entity.user.AdminUser
|
||||
import cn.bunny.dao.entity.system.AdminUser
|
||||
import lombok.Getter
|
||||
import lombok.Setter
|
||||
import org.springframework.security.core.GrantedAuthority
|
||||
|
|
|
@ -27,10 +27,7 @@ class TokenAuthenticationFilter(private val redisTemplate: RedisTemplate<Any, An
|
|||
|
||||
// 自定义实现内容
|
||||
val authentication = getAuthentication(request)
|
||||
if (authentication != null) {
|
||||
// 设置用户详细信息
|
||||
SecurityContextHolder.getContext().authentication = authentication
|
||||
}
|
||||
SecurityContextHolder.getContext().authentication = authentication
|
||||
|
||||
chain.doFilter(request, response)
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
package cn.bunny.services.security.filter
|
||||
|
||||
import cn.bunny.common.service.utils.ResponseUtil.Companion.out
|
||||
import cn.bunny.dao.dto.user.LoginDto
|
||||
import cn.bunny.dao.pojo.constant.RedisUserConstant.Companion.getAdminLoginInfoPrefix
|
||||
import cn.bunny.dao.dto.system.LoginDto
|
||||
import cn.bunny.dao.pojo.constant.RedisUserConstant.Companion.getAdminUserEmailCodePrefix
|
||||
import cn.bunny.dao.pojo.result.Result
|
||||
import cn.bunny.dao.pojo.result.ResultCodeEnum
|
||||
import cn.bunny.services.security.handelr.SecurityAuthenticationFailureHandler
|
||||
import cn.bunny.services.security.handelr.SecurityAuthenticationSuccessHandler
|
||||
import cn.bunny.services.security.service.CustomUserDetailsService
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import jakarta.servlet.FilterChain
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import jakarta.servlet.http.HttpServletResponse
|
||||
|
@ -20,9 +20,7 @@ import org.springframework.security.core.Authentication
|
|||
import org.springframework.security.core.AuthenticationException
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
/**
|
||||
|
@ -46,7 +44,7 @@ class TokenLoginFilterService(
|
|||
this.setAuthenticationFailureHandler(SecurityAuthenticationFailureHandler())
|
||||
this.setPostOnly(false)
|
||||
// ? 指定登录接口及提交方式,可以指定任意路径
|
||||
this.setRequiresAuthenticationRequestMatcher(AntPathRequestMatcher("/*/login", HttpMethod.POST.name()))
|
||||
this.setRequiresAuthenticationRequestMatcher(AntPathRequestMatcher("/admin/login", HttpMethod.POST.name()))
|
||||
this.authenticationManager = authenticationConfiguration.authenticationManager
|
||||
// 依赖注入
|
||||
this.redisTemplate = redisTemplate
|
||||
|
@ -54,51 +52,45 @@ class TokenLoginFilterService(
|
|||
}
|
||||
|
||||
/**
|
||||
* * 登录认证,获取输入的用户名和密码,调用方法认证
|
||||
* 接受前端login登录参数
|
||||
* 在这里可以设置短信验证登录
|
||||
* * 登录认证,获取输入的用户名和密码
|
||||
*
|
||||
*/
|
||||
@Throws(AuthenticationException::class)
|
||||
override fun attemptAuthentication(request: HttpServletRequest, response: HttpServletResponse): Authentication? {
|
||||
try {
|
||||
// 获取用户信息相关内容
|
||||
val loginDto = LoginDto()
|
||||
loginDto.username = "admin"
|
||||
loginDto.password = "password"
|
||||
// 获取用户信息
|
||||
loginDto = ObjectMapper().readValue(request.inputStream, LoginDto::class.java)
|
||||
|
||||
// 封装对象,将用户名密码传入
|
||||
val authenticationToken: Authentication = UsernamePasswordAuthenticationToken(loginDto.username, loginDto.password)
|
||||
return authenticationManager.authenticate(authenticationToken)
|
||||
} catch (e: IOException) {
|
||||
throw RuntimeException(e.localizedMessage)
|
||||
}
|
||||
// 获取登录参数
|
||||
val emailCode = loginDto.emailCode?.lowercase()
|
||||
val username = loginDto.username
|
||||
val password = loginDto.password
|
||||
|
||||
// 获取Redis中邮箱验证码,并判断是否存在或过期
|
||||
val redisEmailCode = redisTemplate.opsForValue()[getAdminUserEmailCodePrefix(username!!)]
|
||||
redisEmailCode ?: out(response, Result.error(ResultCodeEnum.EMAIL_CODE_EMPTY))
|
||||
|
||||
// 判断邮箱验证码是否和用户传入的验证码一致
|
||||
if (emailCode != redisEmailCode?.toString()?.lowercase()) out(response, Result.error(ResultCodeEnum.EMAIL_CODE_NOT_MATCHING))
|
||||
|
||||
// 封装对象,将用户名传入
|
||||
val authenticationToken: Authentication = UsernamePasswordAuthenticationToken(username, password)
|
||||
return authenticationManager.authenticate(authenticationToken)
|
||||
}
|
||||
|
||||
/**
|
||||
* * 认证成功调用方法
|
||||
* 返回登录成功后的信息
|
||||
*/
|
||||
override fun successfulAuthentication(
|
||||
request: HttpServletRequest,
|
||||
response: HttpServletResponse,
|
||||
chain: FilterChain,
|
||||
auth: Authentication
|
||||
) {
|
||||
override fun successfulAuthentication(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain, auth: Authentication) {
|
||||
// 封装返回对象
|
||||
val loginAdminVo = customUserDetailsService.login(loginDto)
|
||||
|
||||
// 判断用户是否被锁定
|
||||
if (loginAdminVo.status!!) {
|
||||
if (loginAdminVo.status == 1.toByte()) {
|
||||
out(response, Result.error(ResultCodeEnum.FAIL_NO_ACCESS_DENIED_USER_LOCKED))
|
||||
return
|
||||
}
|
||||
|
||||
// 将值存入Redis中
|
||||
redisTemplate.opsForValue()[getAdminLoginInfoPrefix(loginAdminVo.email!!), loginAdminVo, 15] =
|
||||
TimeUnit.DAYS
|
||||
// 将Redis中验证码删除
|
||||
redisTemplate.delete(getAdminUserEmailCodePrefix(loginAdminVo.email!!))
|
||||
|
||||
// 返回登录信息
|
||||
out(response, Result.success(loginAdminVo))
|
||||
}
|
||||
|
@ -117,6 +109,7 @@ class TokenLoginFilterService(
|
|||
val username = loginDto.username
|
||||
|
||||
when {
|
||||
// 判断用户名或密码为空
|
||||
password.isNullOrBlank() || username.isNullOrBlank() -> out(response, Result.error(ResultCodeEnum.USERNAME_OR_PASSWORD_NOT_EMPTY))
|
||||
else -> out(response, Result.error(null, ResultCodeEnum.LOGIN_ERROR))
|
||||
}
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
package cn.bunny.services.security.service
|
||||
|
||||
import org.springframework.security.authorization.AuthorizationManager
|
||||
import org.springframework.security.web.access.intercept.RequestAuthorizationContext
|
||||
|
||||
interface CustomAuthorizationManagerService : AuthorizationManager<RequestAuthorizationContext?>
|
|
@ -1,6 +1,6 @@
|
|||
package cn.bunny.services.security.service
|
||||
|
||||
import cn.bunny.dao.dto.user.LoginDto
|
||||
import cn.bunny.dao.dto.system.LoginDto
|
||||
import cn.bunny.dao.vo.user.LoginVo
|
||||
import org.springframework.security.core.userdetails.UserDetails
|
||||
import org.springframework.security.core.userdetails.UserDetailsService
|
||||
|
|
|
@ -1,18 +1,14 @@
|
|||
package cn.bunny.services.security.service.impl;
|
||||
|
||||
import cn.bunny.common.service.utils.JwtHelper;
|
||||
import cn.bunny.services.security.service.CustomAuthorizationManagerService;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
package cn.bunny.services.security.service.impl
|
||||
|
||||
import cn.bunny.common.service.utils.JwtHelper.getUserId
|
||||
import lombok.extern.slf4j.Slf4j
|
||||
import org.springframework.security.authorization.AuthorizationDecision
|
||||
import org.springframework.security.authorization.AuthorizationManager
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.GrantedAuthority
|
||||
import org.springframework.security.web.access.intercept.RequestAuthorizationContext
|
||||
import org.springframework.stereotype.Component
|
||||
import java.util.function.Supplier
|
||||
|
||||
/**
|
||||
* 自定义权限判断
|
||||
|
@ -20,28 +16,26 @@ import java.util.function.Supplier;
|
|||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class CustomAuthorizationManagerServiceImpl implements CustomAuthorizationManagerService {
|
||||
|
||||
@Override
|
||||
public void verify(Supplier<Authentication> authentication, RequestAuthorizationContext requestAuthorizationContext) {
|
||||
CustomAuthorizationManagerService.super.verify(authentication, requestAuthorizationContext);
|
||||
class CustomAuthorizationManagerServiceImpl : AuthorizationManager<RequestAuthorizationContext> {
|
||||
override fun verify(authentication: Supplier<Authentication>, requestAuthorizationContext: RequestAuthorizationContext) {
|
||||
super.verify(authentication, requestAuthorizationContext)
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext context) {
|
||||
override fun check(authentication: Supplier<Authentication>, context: RequestAuthorizationContext): AuthorizationDecision {
|
||||
// 用户的token和用户id、请求Url
|
||||
HttpServletRequest request = context.getRequest();
|
||||
String token = request.getHeader("token");
|
||||
val request = context.request
|
||||
val token = request.getHeader("token")
|
||||
// 用户id
|
||||
Long userId = JwtHelper.getUserId(token);
|
||||
val userId = getUserId(token)
|
||||
// 请求地址
|
||||
String requestURI = request.getRequestURI();
|
||||
val requestURI = request.requestURI
|
||||
// 请求方式
|
||||
String method = request.getMethod();
|
||||
val method = request.method
|
||||
// 角色代码列表
|
||||
List<String> roleCodeList = authentication.get().getAuthorities().stream().map(GrantedAuthority::getAuthority).toList();
|
||||
val roleCodeList = authentication.get().authorities.stream().map { obj: GrantedAuthority -> obj.authority }
|
||||
.toList()
|
||||
|
||||
return new AuthorizationDecision(hasRoleList(requestURI, method, userId));
|
||||
return AuthorizationDecision(hasRoleList(requestURI, method, userId))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -51,7 +45,7 @@ public class CustomAuthorizationManagerServiceImpl implements CustomAuthorizatio
|
|||
* @param method 请求方式
|
||||
* @param userId 用户id
|
||||
*/
|
||||
private Boolean hasRoleList(String requestURI, String method, Long userId) {
|
||||
return true;
|
||||
private fun hasRoleList(requestURI: String, method: String, userId: Long?): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,36 +1,43 @@
|
|||
package cn.bunny.services.security.service.impl
|
||||
|
||||
import cn.bunny.dao.dto.user.LoginDto
|
||||
import cn.bunny.dao.entity.user.AdminUser
|
||||
import cn.bunny.common.service.exception.BunnyException
|
||||
import cn.bunny.dao.dto.system.LoginDto
|
||||
import cn.bunny.dao.entity.system.AdminUser
|
||||
import cn.bunny.dao.pojo.result.ResultCodeEnum
|
||||
import cn.bunny.dao.vo.user.LoginVo
|
||||
import cn.bunny.services.factory.UserFactory
|
||||
import cn.bunny.services.mapper.UserMapper
|
||||
import cn.bunny.services.security.custom.CustomUser
|
||||
import cn.bunny.services.security.service.CustomUserDetailsService
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.SFunction
|
||||
import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.security.core.authority.AuthorityUtils
|
||||
import org.springframework.security.core.userdetails.UserDetails
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.util.DigestUtils
|
||||
|
||||
@Component
|
||||
class CustomUserDetailsServiceImpl : CustomUserDetailsService {
|
||||
@Autowired
|
||||
private val userMapper: UserMapper? = null
|
||||
private lateinit var userFactory: UserFactory
|
||||
|
||||
@Autowired
|
||||
private lateinit var userMapper: UserMapper
|
||||
|
||||
|
||||
@Throws(UsernameNotFoundException::class)
|
||||
override fun loadUserByUsername(username: String): UserDetails {
|
||||
// 根据邮箱查询用户名
|
||||
val user = userMapper!!.selectOne(
|
||||
Wrappers.lambdaQuery<AdminUser>().eq(SFunction<AdminUser, Any> { obj: AdminUser -> obj.email }, username)
|
||||
)
|
||||
// 都为空抛出异常,用户不存在
|
||||
if (user == null) {
|
||||
throw UsernameNotFoundException("")
|
||||
}
|
||||
// 查询用户相关内容
|
||||
val queryWrapper = KtQueryWrapper(AdminUser()).eq(AdminUser::email, username)
|
||||
.or()
|
||||
.eq(AdminUser::username, username)
|
||||
|
||||
// 查询所有的角色
|
||||
// 根据邮箱查询用户名
|
||||
val user = userMapper.selectOne(queryWrapper)
|
||||
user ?: throw UsernameNotFoundException("")
|
||||
|
||||
// TODO 查询所有的角色
|
||||
return CustomUser(user, AuthorityUtils.createAuthorityList(listOf("admin", "common")))
|
||||
}
|
||||
|
||||
|
@ -41,7 +48,18 @@ class CustomUserDetailsServiceImpl : CustomUserDetailsService {
|
|||
* @return 登录后结果返回
|
||||
*/
|
||||
override fun login(loginDto: LoginDto): LoginVo {
|
||||
// 自定义登录逻辑
|
||||
return LoginVo()
|
||||
val username = loginDto.username
|
||||
val password = loginDto.password
|
||||
|
||||
// 查询用户相关内容
|
||||
val queryWrapper = KtQueryWrapper(AdminUser()).eq(AdminUser::email, username).or()
|
||||
.eq(AdminUser::username, username)
|
||||
val user = userMapper.selectOne(queryWrapper)
|
||||
|
||||
// 对登录密码进行md5加密判断,是否与数据库中一致
|
||||
val md5Password: String = DigestUtils.md5DigestAsHex(password!!.byteInputStream())
|
||||
if (!user.password.equals(md5Password)) throw BunnyException(ResultCodeEnum.LOGIN_ERROR)
|
||||
|
||||
return userFactory.buildUserVo(user, loginDto.readMeDay)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package cn.bunny.services.service;
|
||||
|
||||
import cn.bunny.dao.entity.system.EmailTemplate;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
public interface EmailTemplateService extends IService<EmailTemplate> {
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package cn.bunny.services.service;
|
||||
|
||||
import cn.bunny.dao.entity.system.EmailUsers;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 邮箱发送表 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
public interface EmailUsersService extends IService<EmailUsers> {
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package cn.bunny.services.service;
|
||||
|
||||
import cn.bunny.dao.entity.system.MenuIcon;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统菜单图标 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
public interface MenuIconService extends IService<MenuIcon> {
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package cn.bunny.services.service;
|
||||
|
||||
import cn.bunny.dao.entity.system.Router;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统菜单表 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
public interface RouterService extends IService<Router> {
|
||||
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
package cn.bunny.services.service;
|
||||
|
||||
import cn.bunny.dao.entity.user.AdminUser;
|
||||
import cn.bunny.dao.entity.system.AdminUser;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
@ -13,4 +14,10 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
|||
*/
|
||||
public interface UserService extends IService<AdminUser> {
|
||||
|
||||
/**
|
||||
* 登录发送邮件验证码
|
||||
*
|
||||
* @param email 邮箱
|
||||
*/
|
||||
void sendLoginEmail(@NotNull String email);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package cn.bunny.services.service.impl;
|
||||
|
||||
import cn.bunny.dao.entity.system.EmailTemplate;
|
||||
import cn.bunny.services.mapper.EmailTemplateMapper;
|
||||
import cn.bunny.services.service.EmailTemplateService;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
@Service
|
||||
public class EmailTemplateServiceImpl extends ServiceImpl<EmailTemplateMapper, EmailTemplate> implements EmailTemplateService {
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package cn.bunny.services.service.impl
|
||||
|
||||
import cn.bunny.dao.entity.system.EmailUsers
|
||||
import cn.bunny.services.mapper.EmailUsersMapper
|
||||
import cn.bunny.services.service.EmailUsersService
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* 邮箱发送表 服务实现类
|
||||
*
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
@Service
|
||||
class EmailUsersServiceImpl : ServiceImpl<EmailUsersMapper?, EmailUsers?>(), EmailUsersService
|
|
@ -0,0 +1,20 @@
|
|||
package cn.bunny.services.service.impl;
|
||||
|
||||
import cn.bunny.dao.entity.system.MenuIcon;
|
||||
import cn.bunny.services.mapper.MenuIconMapper;
|
||||
import cn.bunny.services.service.MenuIconService;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统菜单图标 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
@Service
|
||||
public class MenuIconServiceImpl extends ServiceImpl<MenuIconMapper, MenuIcon> implements MenuIconService {
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package cn.bunny.services.service.impl;
|
||||
|
||||
import cn.bunny.dao.entity.system.Router;
|
||||
import cn.bunny.services.mapper.RouterMapper;
|
||||
import cn.bunny.services.service.RouterService;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统菜单表 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
@Service
|
||||
public class RouterServiceImpl extends ServiceImpl<RouterMapper, Router> implements RouterService {
|
||||
|
||||
}
|
|
@ -1,20 +1,61 @@
|
|||
package cn.bunny.services.service.impl;
|
||||
package cn.bunny.services.service.impl
|
||||
|
||||
import cn.bunny.dao.entity.user.AdminUser;
|
||||
import cn.bunny.services.mapper.UserMapper;
|
||||
import cn.bunny.services.service.UserService;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
import cn.bunny.common.service.exception.BunnyException
|
||||
import cn.bunny.dao.entity.system.AdminUser
|
||||
import cn.bunny.dao.entity.system.EmailUsers
|
||||
import cn.bunny.dao.pojo.constant.RedisUserConstant
|
||||
import cn.bunny.dao.pojo.email.EmailSendInit
|
||||
import cn.bunny.dao.pojo.result.ResultCodeEnum
|
||||
import cn.bunny.services.factory.EmailFactory
|
||||
import cn.bunny.services.mapper.EmailUsersMapper
|
||||
import cn.bunny.services.mapper.UserMapper
|
||||
import cn.bunny.services.service.UserService
|
||||
import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
|
||||
import org.springframework.beans.BeanUtils
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.data.redis.core.RedisTemplate
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户信息 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-09-26
|
||||
*/
|
||||
@Service
|
||||
public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implements UserService {
|
||||
@Transactional
|
||||
internal class UserServiceImpl : ServiceImpl<UserMapper?, AdminUser?>(), UserService {
|
||||
@Autowired
|
||||
private lateinit var redisTemplate: RedisTemplate<Any, Any>
|
||||
|
||||
@Autowired
|
||||
private lateinit var emailUsersMapper: EmailUsersMapper
|
||||
|
||||
@Autowired
|
||||
private lateinit var emailFactory: EmailFactory
|
||||
|
||||
/**
|
||||
* 登录发送邮件验证码
|
||||
*
|
||||
* @param email 邮箱
|
||||
*/
|
||||
override fun sendLoginEmail(email: String) {
|
||||
// 查找数据库默认发送邮件用户
|
||||
val emailUsers: EmailUsers = emailUsersMapper.selectOne(KtQueryWrapper(EmailUsers()).eq(EmailUsers::isDefault, 1))
|
||||
?: throw BunnyException(ResultCodeEnum.EMAIL_USER_TEMPLATE_IS_EMPTY)
|
||||
|
||||
// 构建发送对象
|
||||
val emailSendInit = EmailSendInit()
|
||||
BeanUtils.copyProperties(emailUsers, emailSendInit)
|
||||
emailSendInit.username = emailUsers.email
|
||||
|
||||
// 发送邮件
|
||||
val emailCode = emailFactory.sendmailCode(email, emailSendInit)
|
||||
|
||||
// 将验证码存入Redis中
|
||||
redisTemplate.opsForValue().set(RedisUserConstant.getAdminUserEmailCodePrefix(email), emailCode)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ bunny:
|
|||
password: "02120212"
|
||||
datasource2:
|
||||
host: 106.15.251.123
|
||||
port: 3304
|
||||
sqlData: auth_admin_i18n
|
||||
port: 3305
|
||||
sqlData: auth_i18n
|
||||
username: root
|
||||
password: "02120212"
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
bunny:
|
||||
datasource:
|
||||
datasource1:
|
||||
host: 192.168.3.98
|
||||
port: 3304
|
||||
sqlData: bunny_docs
|
||||
sqlData: auth_admin
|
||||
username: root
|
||||
password: "02120212"
|
||||
datasource2:
|
||||
host: 192.168.3.98
|
||||
port: 3304
|
||||
sqlData: bunny_docs_i18n
|
||||
host: 106.15.251.123
|
||||
port: 3305
|
||||
sqlData: auth_i18n
|
||||
username: root
|
||||
password: "02120212"
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
server:
|
||||
port: 8800
|
||||
port: 7070
|
||||
spring:
|
||||
profiles:
|
||||
active: dev
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.bunny.services.mapper.EmailTemplateMapper">
|
||||
|
||||
<!-- 通用查询映射结果 -->
|
||||
<resultMap id="BaseResultMap" type="cn.bunny.dao.entity.system.EmailTemplate">
|
||||
<id column="id" property="id"/>
|
||||
<result column="template_name" property="templateName"/>
|
||||
<result column="subject" property="subject"/>
|
||||
<result column="body" property="body"/>
|
||||
<result column="type" property="type"/>
|
||||
<result column="is_default" property="isDefault"/>
|
||||
<result column="create_time" property="createTime"/>
|
||||
<result column="update_time" property="updateTime"/>
|
||||
<result column="create_user" property="createUser"/>
|
||||
<result column="update_user" property="updateUser"/>
|
||||
<result column="is_deleted" property="isDeleted"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 通用查询结果列 -->
|
||||
<sql id="Base_Column_List">
|
||||
id, template_name, subject, body, type, is_default, create_time, update_time, create_user, update_user, is_deleted
|
||||
</sql>
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.bunny.services.mapper.EmailUsersMapper">
|
||||
|
||||
<!-- 通用查询映射结果 -->
|
||||
<resultMap id="BaseResultMap" type="cn.bunny.dao.entity.system.EmailUsers">
|
||||
<id column="id" property="id"/>
|
||||
<result column="email" property="email"/>
|
||||
<result column="email_template" property="emailTemplate"/>
|
||||
<result column="password" property="password"/>
|
||||
<result column="host" property="host"/>
|
||||
<result column="port" property="port"/>
|
||||
<result column="smtp_agreement" property="smtpAgreement"/>
|
||||
<result column="is_default" property="isDefault"/>
|
||||
<result column="create_time" property="createTime"/>
|
||||
<result column="update_time" property="updateTime"/>
|
||||
<result column="create_user" property="createUser"/>
|
||||
<result column="update_user" property="updateUser"/>
|
||||
<result column="is_deleted" property="isDeleted"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 通用查询结果列 -->
|
||||
<sql id="Base_Column_List">
|
||||
id, email, email_template, password, host, port, smtp_agreement, is_default, create_time, update_time, create_user, update_user, is_deleted
|
||||
</sql>
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.bunny.services.mapper.MenuIconMapper">
|
||||
|
||||
<!-- 通用查询映射结果 -->
|
||||
<resultMap id="BaseResultMap" type="cn.bunny.dao.entity.system.MenuIcon">
|
||||
<id column="id" property="id"/>
|
||||
<result column="icon_name" property="iconName"/>
|
||||
<result column="create_user" property="createUser"/>
|
||||
<result column="update_user" property="updateUser"/>
|
||||
<result column="create_time" property="createTime"/>
|
||||
<result column="update_time" property="updateTime"/>
|
||||
<result column="is_deleted" property="isDeleted"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 通用查询结果列 -->
|
||||
<sql id="Base_Column_List">
|
||||
id, icon_name, create_user, update_user, create_time, update_time, is_deleted
|
||||
</sql>
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.bunny.services.mapper.RouterMapper">
|
||||
|
||||
<!-- 通用查询映射结果 -->
|
||||
<resultMap id="BaseResultMap" type="cn.bunny.dao.entity.system.Router">
|
||||
<id column="id" property="id"/>
|
||||
<result column="router_path" property="routerPath"/>
|
||||
<result column="route_name" property="routeName"/>
|
||||
<result column="parent_id" property="parentId"/>
|
||||
<result column="title" property="title"/>
|
||||
<result column="icon" property="icon"/>
|
||||
<result column="router_rank" property="routerRank"/>
|
||||
<result column="visible" property="visible"/>
|
||||
<result column="create_user" property="createUser"/>
|
||||
<result column="update_user" property="updateUser"/>
|
||||
<result column="create_time" property="createTime"/>
|
||||
<result column="update_time" property="updateTime"/>
|
||||
<result column="is_deleted" property="isDeleted"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 通用查询结果列 -->
|
||||
<sql id="Base_Column_List">
|
||||
id, router_path, route_name, parent_id, title, icon, router_rank, visible, create_user, update_user, create_time, update_time, is_deleted
|
||||
</sql>
|
||||
|
||||
</mapper>
|
|
@ -3,7 +3,7 @@
|
|||
<mapper namespace="cn.bunny.services.mapper.UserMapper">
|
||||
|
||||
<!-- 通用查询映射结果 -->
|
||||
<resultMap id="BaseResultMap" type="cn.bunny.dao.entity.user.AdminUser">
|
||||
<resultMap id="BaseResultMap" type="cn.bunny.dao.entity.system.AdminUser">
|
||||
<id column="id" property="id"/>
|
||||
<result column="username" property="username"/>
|
||||
<result column="nick_name" property="nickName"/>
|
||||
|
|
Loading…
Reference in New Issue