Add login IP record
This commit is contained in:
@@ -2,11 +2,20 @@ drop table if exists t_user;
|
||||
|
||||
create table if not exists t_user
|
||||
(
|
||||
id bigint not null primary key,
|
||||
username varchar(20) not null comment '用户名',
|
||||
password char(70) not null comment '密码',
|
||||
enable int not null comment '启用',
|
||||
deleted bigint not null default 0,
|
||||
version int not null default 0,
|
||||
id bigint not null primary key,
|
||||
username varchar(20) not null comment '用户名',
|
||||
password char(70) not null comment '密码',
|
||||
locking int not null comment '锁定',
|
||||
expiration datetime comment '过期时间',
|
||||
credentials_expiration datetime comment '认证过期时间',
|
||||
enable int not null comment '启用',
|
||||
last_login_time datetime comment '上次登录时间',
|
||||
last_login_ip varchar(128) comment '上次登录 IP',
|
||||
create_time datetime not null default (utc_timestamp()) comment '创建时间',
|
||||
update_time datetime not null default (utc_timestamp()) comment '修改时间',
|
||||
deleted bigint not null default 0,
|
||||
version int not null default 0,
|
||||
constraint t_user_unique unique (username, deleted)
|
||||
) comment '用户';
|
||||
) comment '用户表';
|
||||
|
||||
insert into t_user (id, username, password, locking, enable) value (0, 'admin', '$2a$10$3wDGdzTZlC..7eY6u2XM5u78xUQo0z5Sj5yOpneD4QJ0q/TA5TY0S', 0, 1)
|
||||
@@ -4,7 +4,10 @@ import io.swagger.v3.oas.annotations.Operation
|
||||
import io.swagger.v3.oas.annotations.tags.Tag
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import jakarta.validation.Valid
|
||||
import org.springframework.web.bind.annotation.*
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import top.fatweb.api.annotation.ApiVersion
|
||||
import top.fatweb.api.converter.UserConverter
|
||||
import top.fatweb.api.entity.common.ResponseCode
|
||||
@@ -19,11 +22,11 @@ import top.fatweb.api.util.WebUtil
|
||||
class AuthenticationController(val authenticationService: IAuthenticationService, val userConverter: UserConverter) {
|
||||
@Operation(summary = "登录")
|
||||
@PostMapping("/login")
|
||||
fun login(@Valid @RequestBody loginParam: LoginParam) =
|
||||
fun login(request: HttpServletRequest, @Valid @RequestBody loginParam: LoginParam) =
|
||||
ResponseResult.success(
|
||||
ResponseCode.SYSTEM_LOGIN_SUCCESS,
|
||||
"Login success",
|
||||
authenticationService.login(userConverter.loginParamToUser(loginParam))
|
||||
authenticationService.login(request, userConverter.loginParamToUser(loginParam))
|
||||
)
|
||||
|
||||
@Operation(summary = "登出")
|
||||
|
||||
@@ -4,6 +4,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo
|
||||
import org.springframework.security.core.GrantedAuthority
|
||||
import org.springframework.security.core.userdetails.UserDetails
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneOffset
|
||||
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
|
||||
class LoginUser() : UserDetails {
|
||||
@@ -25,20 +27,22 @@ class LoginUser() : UserDetails {
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
override fun getPassword(): String? = user.password
|
||||
override fun getPassword() = user.password
|
||||
|
||||
@JsonIgnore
|
||||
override fun getUsername(): String? = user.username
|
||||
override fun getUsername() = user.username
|
||||
|
||||
@JsonIgnore
|
||||
override fun isAccountNonExpired(): Boolean = true
|
||||
override fun isAccountNonExpired() =
|
||||
user.expiration == null || user.expiration!!.isAfter(LocalDateTime.now(ZoneOffset.UTC))
|
||||
|
||||
@JsonIgnore
|
||||
override fun isAccountNonLocked(): Boolean = true
|
||||
override fun isAccountNonLocked() = user.locking == 0
|
||||
|
||||
@JsonIgnore
|
||||
override fun isCredentialsNonExpired(): Boolean = true
|
||||
override fun isCredentialsNonExpired() =
|
||||
user.credentialsExpiration == null || user.credentialsExpiration!!.isAfter(LocalDateTime.now(ZoneOffset.UTC))
|
||||
|
||||
@JsonIgnore
|
||||
override fun isEnabled(): Boolean = user.enable == 1
|
||||
override fun isEnabled() = user.enable == 1
|
||||
}
|
||||
@@ -2,10 +2,11 @@ package top.fatweb.api.entity.permission
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*
|
||||
import java.io.Serializable
|
||||
import java.time.LocalDateTime
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户
|
||||
* 用户表
|
||||
* </p>
|
||||
*
|
||||
* @author FatttSnake
|
||||
@@ -13,7 +14,8 @@ import java.io.Serializable
|
||||
*/
|
||||
@TableName("t_user")
|
||||
class User() : Serializable {
|
||||
constructor(username: String, password: String, enable: Boolean = true) : this() {
|
||||
constructor(id: Long?, username: String, password: String, enable: Boolean = true) : this() {
|
||||
this.id = id
|
||||
this.username = username
|
||||
this.password = password
|
||||
this.enable = if (enable) 1 else 0
|
||||
@@ -34,12 +36,54 @@ class User() : Serializable {
|
||||
@TableField("password")
|
||||
var password: String? = null
|
||||
|
||||
/**
|
||||
* 锁定
|
||||
*/
|
||||
@TableField("locking")
|
||||
var locking: Int? = null
|
||||
|
||||
/**
|
||||
* 过期时间
|
||||
*/
|
||||
@TableField("expiration")
|
||||
var expiration: LocalDateTime? = null
|
||||
|
||||
/**
|
||||
* 认证过期时间
|
||||
*/
|
||||
@TableField("credentials_expiration")
|
||||
var credentialsExpiration: LocalDateTime? = null
|
||||
|
||||
/**
|
||||
* 启用
|
||||
*/
|
||||
@TableField("enable")
|
||||
var enable: Int? = null
|
||||
|
||||
/**
|
||||
* 上次登录时间
|
||||
*/
|
||||
@TableField("last_login_time")
|
||||
var lastLoginTime: LocalDateTime? = null
|
||||
|
||||
/**
|
||||
* 上次登录 IP
|
||||
*/
|
||||
@TableField("last_login_ip")
|
||||
var lastLoginIp: String? = null
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField("create_time")
|
||||
var createTime: LocalDateTime? = null
|
||||
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
@TableField("update_time")
|
||||
var updateTime: LocalDateTime? = null
|
||||
|
||||
@TableField("deleted")
|
||||
@TableLogic
|
||||
var deleted: Long? = null
|
||||
@@ -49,6 +93,6 @@ class User() : Serializable {
|
||||
var version: Int? = null
|
||||
|
||||
override fun toString(): String {
|
||||
return "User{id=$id, username=$username, password=$password, enable=$enable, deleted=$deleted, version=$version}"
|
||||
return "User(id=$id, username=$username, password=$password, locking=$locking, expiration=$expiration, credentialsExpiration=$credentialsExpiration, enable=$enable, lastLoginTime=$lastLoginTime, lastLoginIp=$lastLoginIp, createTime=$createTime, updateTime=$updateTime, deleted=$deleted, version=$version)"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package top.fatweb.api.service.permission
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import top.fatweb.api.entity.permission.User
|
||||
import top.fatweb.api.vo.LoginVo
|
||||
import top.fatweb.api.vo.TokenVo
|
||||
|
||||
interface IAuthenticationService {
|
||||
fun login(user: User): LoginVo
|
||||
fun login(request: HttpServletRequest, user: User): LoginVo
|
||||
|
||||
fun logout(token: String): Boolean
|
||||
|
||||
|
||||
@@ -1,30 +1,46 @@
|
||||
package top.fatweb.api.service.permission.impl
|
||||
|
||||
import com.baomidou.mybatisplus.extension.kotlin.KtUpdateWrapper
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.security.authentication.AuthenticationManager
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
||||
import org.springframework.stereotype.Service
|
||||
import top.fatweb.api.constant.SecurityConstants
|
||||
import top.fatweb.api.entity.permission.LoginUser
|
||||
import top.fatweb.api.entity.permission.User
|
||||
import top.fatweb.api.service.IUserService
|
||||
import top.fatweb.api.service.permission.IAuthenticationService
|
||||
import top.fatweb.api.util.JwtUtil
|
||||
import top.fatweb.api.util.RedisUtil
|
||||
import top.fatweb.api.util.WebUtil
|
||||
import top.fatweb.api.vo.LoginVo
|
||||
import top.fatweb.api.vo.TokenVo
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneOffset
|
||||
|
||||
@Service
|
||||
class AuthenticationServiceImpl(
|
||||
private val authenticationManager: AuthenticationManager,
|
||||
private val redisUtil: RedisUtil
|
||||
private val redisUtil: RedisUtil,
|
||||
private val userService: IUserService
|
||||
) : IAuthenticationService {
|
||||
override fun login(user: User): LoginVo {
|
||||
private val logger: Logger = LoggerFactory.getLogger(this::class.java)
|
||||
|
||||
override fun login(request: HttpServletRequest, user: User): LoginVo {
|
||||
val usernamePasswordAuthenticationToken = UsernamePasswordAuthenticationToken(user.username, user.password)
|
||||
val authentication = authenticationManager.authenticate(usernamePasswordAuthenticationToken)
|
||||
authentication ?: let {
|
||||
throw RuntimeException("Login failed")
|
||||
}
|
||||
|
||||
logger.info("用户登录 [用户名: '{}', IP: '{}']", user.username, request.remoteAddr)
|
||||
userService.update(User().apply {
|
||||
lastLoginIp = request.remoteAddr
|
||||
lastLoginTime = LocalDateTime.now(ZoneOffset.UTC)
|
||||
}, KtUpdateWrapper(User()).eq(User::username, user.username))
|
||||
|
||||
val loginUser = authentication.principal as LoginUser
|
||||
loginUser.user.password = ""
|
||||
val userId = loginUser.user.id.toString()
|
||||
|
||||
@@ -3,12 +3,15 @@ package top.fatweb.api
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension
|
||||
import top.fatweb.api.constant.SecurityConstants
|
||||
import top.fatweb.api.util.JwtUtil
|
||||
|
||||
@ExtendWith(SpringExtension::class)
|
||||
class FatWebApiApplicationTests {
|
||||
private val logger: Logger = LoggerFactory.getLogger(this::class.java)
|
||||
|
||||
@Test
|
||||
fun removePrefixTest() {
|
||||
@@ -20,4 +23,12 @@ class FatWebApiApplicationTests {
|
||||
val jwt = JwtUtil.createJwt("User")
|
||||
assertEquals("User", jwt?.let { JwtUtil.parseJwt(it).subject })
|
||||
}
|
||||
|
||||
/*
|
||||
@Test
|
||||
fun generatePassword() {
|
||||
val passwordEncoder = BCryptPasswordEncoder()
|
||||
logger.info(passwordEncoder.encode("admin@dev"))
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user