feat(新增): 用户认证

This commit is contained in:
bunny 2024-09-27 10:38:48 +08:00
parent 175e238852
commit 91bf18844a
9 changed files with 71 additions and 20 deletions

View File

@ -30,7 +30,7 @@ open class BaseContext {
}
@JvmStatic
fun getLoginVo(): LoginVo? {
fun getLoginVo(): LoginVo {
return loginVo.get()
}

View File

@ -12,13 +12,15 @@ import lombok.NoArgsConstructor
@Schema(name = "EmailTemplateDto", title = "邮箱模板请求内容", description = "邮箱模板请求内容")
class EmailTemplateDto {
@Schema(name = "templateName", title = "模板名称")
var templateName: @NotBlank(message = "模板名称不能为空") String? = null
var templateName: String? = null
@Schema(name = "subject", title = "主题")
var subject: @NotBlank(message = "主题不能为空") String? = null
@NotBlank(message = "主题不能为空")
var subject: String? = null
@Schema(name = "body", title = "邮件内容")
var body: @NotBlank(message = "邮件内容不能为空") String? = null
@NotBlank(message = "邮件内容不能为空")
var body: String? = null
@Schema(name = "type", title = "邮件类型")
var type: String? = null

View File

@ -18,19 +18,23 @@ import lombok.NoArgsConstructor
@Schema(name = "EmailUsersDto", title = "邮箱用户发送基础内容", description = "邮箱用户发送基础内容")
class EmailUsersDto {
@Schema(name = "id", title = "主键")
var id: @NotBlank(message = "id不能为空") Long? = null
@NotBlank(message = "id不能为空")
var id: Long? = null
@Schema(name = "email", title = "邮箱")
var email: @NotBlank(message = "邮箱不能为空") String? = null
@NotBlank(message = "邮箱不能为空")
var email: String? = null
@Schema(name = "password", title = "密码")
var password: @NotBlank(message = "密码不能为空") String? = null
@NotBlank(message = "密码不能为空")
var password: String? = null
@Schema(name = "host", title = "SMTP服务器")
var host: String? = null
@Schema(name = "port", title = "端口号")
var port: @NotNull(message = "端口号不能为空") Int? = null
@NotNull(message = "端口号不能为空")
var port: Int? = null
@Schema(name = "smtpAgreement", title = "邮箱协议")
var smtpAgreement: Int? = null

View File

@ -13,6 +13,7 @@ enum class ResultCodeEnum(val code: Int, val message: String) {
EMAIL_CODE_SEND_SUCCESS(200, "邮箱验证码已发送"),
// 验证错误 201
LOGIN_AUTH(208, "请先登陆"),
USERNAME_OR_PASSWORD_NOT_EMPTY(201, "用户名或密码不能为空"),
EMAIL_CODE_NOT_EMPTY(201, "邮箱验证码不能为空"),
EMAIL_CODE_EMPTY(201, "邮箱验证码过期或不存在"),
@ -28,7 +29,6 @@ enum class ResultCodeEnum(val code: Int, val message: String) {
EMAIL_USER_TEMPLATE_IS_EMPTY(206, "邮件模板为空"),
// 身份过期 208
LOGIN_AUTH(208, "请先登陆"),
AUTHENTICATION_EXPIRED(208, "身份验证过期"),
// 封禁 209

View File

@ -1,6 +1,7 @@
package cn.bunny.services.security.config
import cn.bunny.services.security.custom.CustomPasswordEncoder
import cn.bunny.services.security.filter.NoTokenAuthenticationFilter
import cn.bunny.services.security.filter.TokenAuthenticationFilter
import cn.bunny.services.security.filter.TokenLoginFilterService
import cn.bunny.services.security.handelr.SecurityAccessDeniedHandler
@ -75,6 +76,7 @@ class WebSecurityConfig {
UsernamePasswordAuthenticationFilter::class.java
)
// 其它权限鉴权过滤器
.addFilterAt(NoTokenAuthenticationFilter(redisTemplate), UsernamePasswordAuthenticationFilter::class.java)
.addFilterAt(TokenAuthenticationFilter(redisTemplate), UsernamePasswordAuthenticationFilter::class.java)
// 自定义密码加密器和用户登录
.passwordManagement(customPasswordEncoder).userDetailsService(customUserDetailsService)

View File

@ -0,0 +1,50 @@
package cn.bunny.services.security.filter
import cn.bunny.common.service.context.BaseContext
import cn.bunny.common.service.utils.JwtHelper
import cn.bunny.common.service.utils.ResponseUtil.Companion.out
import cn.bunny.dao.pojo.constant.RedisUserConstant
import cn.bunny.dao.pojo.result.Result
import cn.bunny.dao.pojo.result.ResultCodeEnum
import cn.bunny.dao.vo.user.LoginVo
import jakarta.servlet.FilterChain
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.data.redis.core.RedisTemplate
import org.springframework.web.filter.OncePerRequestFilter
class NoTokenAuthenticationFilter(private val redisTemplate: RedisTemplate<Any, Any?>) : OncePerRequestFilter() {
override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) {
// 判断是否有token
val token = request.getHeader("token") ?: run {
out(response, Result.error(ResultCodeEnum.LOGIN_AUTH))
return@doFilterInternal
}
// 判断token是否过期
val expired = JwtHelper.isExpired(token)
if (expired) {
out(response, Result.error(ResultCodeEnum.AUTHENTICATION_EXPIRED))
return
}
// token存在查找Redis
val username = JwtHelper.getUsername(token)!!
val userId = JwtHelper.getUserId(token)!!
val loginVo: LoginVo? = redisTemplate.opsForValue().get(RedisUserConstant.getAdminLoginInfoPrefix(username)) as LoginVo?
// 判断用户是否禁用
if (loginVo?.status == 1.toByte()) {
out(response, Result.error(ResultCodeEnum.FAIL_NO_ACCESS_DENIED_USER_LOCKED))
return
}
// 设置用户信息
BaseContext.setUsername(username)
BaseContext.setUserId(userId)
BaseContext.setLoginVo(loginVo!!)
// 执行下一个过滤器
doFilter(request, response, filterChain)
}
}

View File

@ -16,14 +16,6 @@ import java.util.function.Consumer
class TokenAuthenticationFilter(private val redisTemplate: RedisTemplate<Any, Any?>) : OncePerRequestFilter() {
@Throws(ServletException::class, IOException::class, BunnyException::class)
override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain) {
val token = request.getHeader("token")
// 判断是否有token如果后面还有过滤器就这样写
// if (token == null) {
// doFilter(request, response, chain)
// return
// }
// 自定义实现内容
val authentication = getAuthentication(request)
@ -31,6 +23,8 @@ class TokenAuthenticationFilter(private val redisTemplate: RedisTemplate<Any, An
chain.doFilter(request, response)
}
// 判断是否有token如果后面还有过滤器就这样写
/**
* * 用户请求判断

View File

@ -36,8 +36,7 @@ class CustomUserDetailsServiceImpl : CustomUserDetailsService {
val queryWrapper = KtQueryWrapper(AdminUser()).eq(AdminUser::email, username).or().eq(AdminUser::username, username)
// 根据邮箱查询用户名
val user = userMapper.selectOne(queryWrapper)
user ?: throw UsernameNotFoundException("用户不存在 ")
val user = userMapper.selectOne(queryWrapper) ?: throw UsernameNotFoundException("用户不存在")
// 根据用户id查询当前用户所有角色
val roleList: List<Role> = roleMapper.selectListByUserId(user.id!!)

View File

@ -95,7 +95,7 @@ internal class UserServiceImpl : ServiceImpl<UserMapper?, AdminUser?>(), UserSer
* * 退出登录
*/
override fun logOut() {
val loginVo = BaseContext.getLoginVo() ?: throw BunnyException(ResultCodeEnum.FAIL_REQUEST_NOT_AUTH)
val loginVo = BaseContext.getLoginVo()
redisTemplate.delete(RedisUserConstant.getAdminLoginInfoPrefix(loginVo.username!!))
}
}