Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
有来技术
youlai-mall
提交
112a8b1d
Y
youlai-mall
项目概览
有来技术
/
youlai-mall
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
Y
youlai-mall
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
112a8b1d
编写于
3月 09, 2021
作者:
H
haoxr
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat:会话强制下线
上级
b01367fb
变更
16
隐藏空白更改
内联
并排
Showing
16 changed file
with
341 addition
and
87 deletion
+341
-87
pom.xml
pom.xml
+8
-1
youlai-admin/admin-api/src/main/java/com/youlai/admin/pojo/domain/LoginRecord.java
...c/main/java/com/youlai/admin/pojo/domain/LoginRecord.java
+30
-0
youlai-admin/admin-boot/pom.xml
youlai-admin/admin-boot/pom.xml
+4
-1
youlai-admin/admin-boot/src/main/java/com/youlai/admin/common/constant/ESConstants.java
...in/java/com/youlai/admin/common/constant/ESConstants.java
+3
-0
youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/DashboardController.java
...java/com/youlai/admin/controller/DashboardController.java
+3
-2
youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/LoginRecordController.java
...va/com/youlai/admin/controller/LoginRecordController.java
+92
-0
youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/TokenController.java
...ain/java/com/youlai/admin/controller/TokenController.java
+57
-0
youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/UserController.java
...main/java/com/youlai/admin/controller/UserController.java
+0
-1
youlai-admin/admin-boot/src/test/java/com/youlai/admin/ElasticSearchTests.java
...ot/src/test/java/com/youlai/admin/ElasticSearchTests.java
+1
-19
youlai-auth/src/main/java/com/youlai/auth/controller/LogoutController.java
...ain/java/com/youlai/auth/controller/LogoutController.java
+2
-2
youlai-common/common-core/src/main/java/com/youlai/common/constant/AuthConstants.java
...c/main/java/com/youlai/common/constant/AuthConstants.java
+18
-3
youlai-common/common-elasticsearch/src/main/java/com/youlai/common/elasticsearch/config/RestHighLevelClientConfig.java
...ommon/elasticsearch/config/RestHighLevelClientConfig.java
+1
-1
youlai-common/common-elasticsearch/src/main/java/com/youlai/common/elasticsearch/service/ElasticSearchService.java
...ai/common/elasticsearch/service/ElasticSearchService.java
+22
-10
youlai-common/common-web/pom.xml
youlai-common/common-web/pom.xml
+12
-6
youlai-common/common-web/src/main/java/com/youlai/common/web/aspect/LoginLogAspect.java
...ain/java/com/youlai/common/web/aspect/LoginLogAspect.java
+36
-35
youlai-common/common-web/src/main/java/com/youlai/common/web/util/IPUtils.java
...web/src/main/java/com/youlai/common/web/util/IPUtils.java
+52
-6
未找到文件。
pom.xml
浏览文件 @
112a8b1d
...
...
@@ -46,9 +46,10 @@
<seata.version>
1.4.1
</seata.version>
<commons-pool2-version>
2.9.0
</commons-pool2-version>
<knife4j.version>
2.0.8
</knife4j.version>
<redisson.version>
3.11.1
</redisson.version>
<logstash-logback-encoder.version>
6.6
</logstash-logback-encoder.version>
<elasticsearch.version>
7.10.1
</elasticsearch.version>
<
redisson.version>
3.11.1
</rediss
on.version>
<
ip2region.version>
1.7.2
</ip2regi
on.version>
</properties>
<dependencies>
...
...
@@ -174,6 +175,12 @@
<version>
${redisson.version}
</version>
</dependency>
<dependency>
<groupId>
org.lionsoul
</groupId>
<artifactId>
ip2region
</artifactId>
<version>
${ip2region.version}
</version>
</dependency>
</dependencies>
</dependencyManagement>
...
...
youlai-
common/common-web/src/main/java/com/youlai/common/web/pojo/domain/LoginLog
.java
→
youlai-
admin/admin-api/src/main/java/com/youlai/admin/pojo/domain/LoginRecord
.java
浏览文件 @
112a8b1d
package
com.youlai.
common.web
.pojo.domain
;
package
com.youlai.
admin
.pojo.domain
;
import
lombok.Data
;
/**
* @Author haoxr
* @Date 2021-03-01 16:45
* @Version 1.0.0
* @author hxr
* @date 2021-03-09
*/
@Data
public
class
LoginLog
{
public
class
LoginRecord
{
private
String
_id
;
private
String
description
;
private
String
clientIP
;
private
String
url
;
private
long
elapsedTime
;
private
String
method
;
private
Object
message
;
private
long
elapsedTime
;
private
String
token
;
private
String
username
;
private
String
loginTime
;
private
Object
result
;
private
String
region
;
}
youlai-admin/admin-boot/pom.xml
浏览文件 @
112a8b1d
...
...
@@ -77,7 +77,10 @@
<artifactId>
spring-boot-starter-web
</artifactId>
</dependency>
<dependency>
<groupId>
com.nimbusds
</groupId>
<artifactId>
nimbus-jose-jwt
</artifactId>
</dependency>
</dependencies>
<build>
...
...
youlai-admin/admin-boot/src/main/java/com/youlai/admin/common/constant/ESConstants.java
浏览文件 @
112a8b1d
...
...
@@ -8,4 +8,7 @@ public interface ESConstants {
String
INDEX_LOGIN_PREFIX
=
"youlai-auth-login-"
;
String
INDEX_LOGIN_PATTERN
=
"youlai-auth-login-*"
;
}
youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/DashboardController.java
浏览文件 @
112a8b1d
...
...
@@ -4,7 +4,7 @@ import cn.hutool.core.convert.Convert;
import
com.youlai.admin.common.constant.ESConstants
;
import
com.youlai.common.elasticsearch.service.ElasticSearchService
;
import
com.youlai.common.result.Result
;
import
com.youlai.common.web.util.I
p
Utils
;
import
com.youlai.common.web.util.I
P
Utils
;
import
com.youlai.common.web.util.RequestUtils
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiOperation
;
...
...
@@ -72,7 +72,7 @@ public class DashboardController {
// 当前用户统计
HttpServletRequest
request
=
RequestUtils
.
getRequest
();
String
clientIP
=
I
pUtils
.
getIpAddr
(
request
);
String
clientIP
=
I
PUtils
.
getClientIP
(
request
);
boolQueryBuilder
.
must
(
QueryBuilders
.
termQuery
(
"clientIP"
,
clientIP
));
Map
<
String
,
Long
>
myCountMap
=
elasticSearchService
.
dateHistogram
(
boolQueryBuilder
,
"date"
,
DateHistogramInterval
.
days
(
1
),
indices
);
...
...
@@ -97,4 +97,5 @@ public class DashboardController {
return
Result
.
success
(
map
);
}
}
youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/LoginRecordController.java
0 → 100644
浏览文件 @
112a8b1d
package
com.youlai.admin.controller
;
import
cn.hutool.core.util.StrUtil
;
import
com.youlai.admin.common.constant.ESConstants
;
import
com.youlai.admin.pojo.domain.LoginRecord
;
import
com.youlai.common.elasticsearch.service.ElasticSearchService
;
import
com.youlai.common.result.Result
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiImplicitParam
;
import
io.swagger.annotations.ApiImplicitParams
;
import
io.swagger.annotations.ApiOperation
;
import
lombok.AllArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.elasticsearch.index.query.BoolQueryBuilder
;
import
org.elasticsearch.index.query.QueryBuilders
;
import
org.elasticsearch.index.query.RangeQueryBuilder
;
import
org.elasticsearch.search.sort.FieldSortBuilder
;
import
org.elasticsearch.search.sort.SortOrder
;
import
org.springframework.web.bind.annotation.*
;
import
java.util.List
;
/**
* @author hxr
* @date 2021-03-09
*/
@Api
(
tags
=
"登录记录"
)
@RestController
@RequestMapping
(
"/api.admin/v1/records/login"
)
@Slf4j
@AllArgsConstructor
public
class
LoginRecordController
{
ElasticSearchService
elasticSearchService
;
@ApiOperation
(
value
=
"列表分页"
,
httpMethod
=
"GET"
)
@ApiImplicitParams
({
@ApiImplicitParam
(
name
=
"page"
,
value
=
"页码"
,
defaultValue
=
"1"
,
paramType
=
"query"
,
dataType
=
"Long"
),
@ApiImplicitParam
(
name
=
"limit"
,
value
=
"每页数量"
,
defaultValue
=
"10"
,
paramType
=
"query"
,
dataType
=
"Long"
),
@ApiImplicitParam
(
name
=
"startDate"
,
value
=
"开始日期"
,
paramType
=
"query"
,
dataType
=
"String"
),
@ApiImplicitParam
(
name
=
"endDate"
,
value
=
"结束日期"
,
paramType
=
"query"
,
dataType
=
"String"
),
@ApiImplicitParam
(
name
=
"clientIP"
,
value
=
"客户端IP"
,
paramType
=
"query"
,
dataType
=
"String"
)
})
@GetMapping
public
Result
list
(
Integer
page
,
Integer
limit
,
String
startDate
,
String
endDate
,
String
clientIP
)
{
// 日期范围
RangeQueryBuilder
rangeQueryBuilder
=
QueryBuilders
.
rangeQuery
(
"date"
);
if
(
StrUtil
.
isNotBlank
(
startDate
))
{
rangeQueryBuilder
.
from
(
startDate
);
}
if
(
StrUtil
.
isNotBlank
(
endDate
))
{
rangeQueryBuilder
.
to
(
endDate
);
}
BoolQueryBuilder
queryBuilder
=
QueryBuilders
.
boolQuery
().
must
(
rangeQueryBuilder
);
if
(
StrUtil
.
isNotBlank
(
clientIP
))
{
queryBuilder
.
must
(
QueryBuilders
.
wildcardQuery
(
"clientIP"
,
"*"
+
clientIP
+
"*"
));
}
// 总记录数
long
count
=
elasticSearchService
.
count
(
queryBuilder
,
ESConstants
.
INDEX_LOGIN_PATTERN
);
// 排序
FieldSortBuilder
sortBuilder
=
new
FieldSortBuilder
(
"@timestamp"
).
order
(
SortOrder
.
DESC
);
// 分页数
List
<
LoginRecord
>
list
=
elasticSearchService
.
search
(
queryBuilder
,
sortBuilder
,
page
,
limit
,
LoginRecord
.
class
,
ESConstants
.
INDEX_LOGIN_PATTERN
);
return
Result
.
success
(
list
,
count
);
}
@ApiOperation
(
value
=
"删除登录记录"
,
httpMethod
=
"DELETE"
)
@ApiImplicitParam
(
name
=
"ids"
,
value
=
"id集合"
,
required
=
true
,
paramType
=
"query"
,
dataType
=
"String"
)
@DeleteMapping
(
"/{ids}"
)
public
Result
delete
(
@PathVariable
String
ids
)
{
return
Result
.
judge
(
true
);
}
}
youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/TokenController.java
0 → 100644
浏览文件 @
112a8b1d
package
com.youlai.admin.controller
;
import
cn.hutool.json.JSONObject
;
import
cn.hutool.json.JSONUtil
;
import
com.nimbusds.jose.JWSObject
;
import
com.youlai.common.constant.AuthConstants
;
import
com.youlai.common.result.Result
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiImplicitParam
;
import
io.swagger.annotations.ApiOperation
;
import
lombok.AllArgsConstructor
;
import
lombok.SneakyThrows
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.logging.log4j.util.Strings
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
org.springframework.web.bind.annotation.*
;
import
java.util.concurrent.TimeUnit
;
/**
* @author hxr
* @date 2021-03-09
*/
@Api
(
tags
=
"令牌接口"
)
@RestController
@RequestMapping
(
"/api.admin/v1/tokens"
)
@Slf4j
@AllArgsConstructor
public
class
TokenController
{
RedisTemplate
redisTemplate
;
@ApiOperation
(
value
=
"强制下线"
,
httpMethod
=
"POST"
)
@ApiImplicitParam
(
name
=
"token"
,
value
=
"访问令牌"
,
required
=
true
,
paramType
=
"query"
,
dataType
=
"String"
)
@PostMapping
(
"/{token}/_invalid"
)
@SneakyThrows
public
Result
invalidToken
(
@PathVariable
String
token
)
{
token
=
token
.
replace
(
AuthConstants
.
AUTHORIZATION_PREFIX
,
Strings
.
EMPTY
);
JWSObject
jwsObject
=
JWSObject
.
parse
(
token
);
String
payload
=
jwsObject
.
getPayload
().
toString
();
JSONObject
jsonObject
=
JSONUtil
.
parseObj
(
payload
);
long
currentTimeSeconds
=
System
.
currentTimeMillis
()
/
1000
;
String
jti
=
jsonObject
.
getStr
(
AuthConstants
.
JWT_JTI
);
// JWT唯一标识
long
exp
=
jsonObject
.
getLong
(
AuthConstants
.
JWT_EXP
);
// JWT过期时间戳
if
(
exp
<
currentTimeSeconds
)
{
// token已过期,无需加入黑名单
return
Result
.
success
();
}
redisTemplate
.
opsForValue
().
set
(
AuthConstants
.
TOKEN_BLACKLIST_PREFIX
+
jti
,
null
,
(
exp
-
currentTimeSeconds
),
TimeUnit
.
SECONDS
);
return
Result
.
success
();
}
}
youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/UserController.java
浏览文件 @
112a8b1d
...
...
@@ -38,7 +38,6 @@ public class UserController extends BaseController {
private
final
ISysUserService
iSysUserService
;
private
final
ISysUserRoleService
iSysUserRoleService
;
private
final
ISysRoleService
iSysRoleService
;
private
final
PasswordEncoder
passwordEncoder
;
private
final
ISysPermissionService
iSysPermissionService
;
...
...
youlai-admin/admin-boot/src/test/java/com/youlai/admin/ElasticSearchTests.java
浏览文件 @
112a8b1d
package
com.youlai.admin
;
import
com.youlai.common.elasticsearch.service.ElasticSearchService
;
import
com.youlai.common.web.pojo.domain.LoginLog
;
import
lombok.extern.slf4j.Slf4j
;
import
org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval
;
import
org.junit.jupiter.api.Test
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
java.util.List
;
import
java.util.Map
;
@SpringBootTest
@Slf4j
public
class
ElasticSearchTests
{
...
...
@@ -19,21 +14,8 @@ public class ElasticSearchTests {
private
ElasticSearchService
elasticSearchService
;
@Test
public
void
search
()
{
List
<
LoginLog
>
list
=
elasticSearchService
.
search
(
null
,
LoginLog
.
class
,
"youlai-auth-login-2021-03-06"
);
System
.
out
.
println
(
list
.
toString
());
}
@Test
public
void
count
(){
public
void
count
()
{
long
count
=
elasticSearchService
.
count
(
null
,
"youlai-auth-login-2021-03-06"
);
log
.
info
(
String
.
valueOf
(
count
));
}
@Test
public
void
group
(){
Map
<
String
,
Long
>
map
=
elasticSearchService
.
dateHistogram
(
null
,
"date"
,
DateHistogramInterval
.
days
(
1
),
"youlai-auth-login-2021-03-07"
,
"youlai-auth-login-2021-03-08"
);
log
.
info
(
map
.
toString
());
}
}
youlai-auth/src/main/java/com/youlai/auth/controller/LogoutController.java
浏览文件 @
112a8b1d
...
...
@@ -27,8 +27,8 @@ public class LogoutController {
@DeleteMapping
(
"/logout"
)
public
Result
logout
()
{
JSONObject
jsonObject
=
RequestUtils
.
getJwtPayload
();
String
jti
=
jsonObject
.
getStr
(
"jti"
);
// JWT唯一标识
long
exp
=
jsonObject
.
getLong
(
"exp"
);
// JWT过期时间戳
String
jti
=
jsonObject
.
getStr
(
AuthConstants
.
JWT_JTI
);
// JWT唯一标识
long
exp
=
jsonObject
.
getLong
(
AuthConstants
.
JWT_EXP
);
// JWT过期时间戳
long
currentTimeSeconds
=
System
.
currentTimeMillis
()
/
1000
;
...
...
youlai-common/common-core/src/main/java/com/youlai/common/constant/AuthConstants.java
浏览文件 @
112a8b1d
...
...
@@ -11,7 +11,7 @@ public interface AuthConstants {
/**
* JWT令牌前缀
*/
String
JWT
_PREFIX
=
"bearer "
;
String
AUTHORIZATION
_PREFIX
=
"bearer "
;
/**
...
...
@@ -24,6 +24,16 @@ public interface AuthConstants {
*/
String
JWT_PAYLOAD_KEY
=
"payload"
;
/**
* JWT ID 唯一标识
*/
String
JWT_JTI
=
"jti"
;
/**
* JWT ID 唯一标识
*/
String
JWT_EXP
=
"exp"
;
/**
* Redis缓存权限规则key
*/
...
...
@@ -51,7 +61,7 @@ public interface AuthConstants {
String
USER_ID_KEY
=
"user_id"
;
String
USER_NAME_KEY
=
"username"
;
String
USER_NAME_KEY
=
"username"
;
String
CLIENT_ID_KEY
=
"client_id"
;
...
...
@@ -83,5 +93,10 @@ public interface AuthConstants {
String
ADMIN_URL_PATTERN
=
"*_/youlai-admin/**"
;
String
LOGOUT_PATH
=
"/youlai-auth/oauth/logout"
;
String
LOGOUT_PATH
=
"/youlai-auth/oauth/logout"
;
String
GRANT_TYPE_KEY
=
"grant_type"
;
String
REFRESH_TOKEN
=
"refresh_token"
;
}
youlai-common/common-elasticsearch/src/main/java/com/youlai/common/elasticsearch/config/RestHighLevelClientConfig.java
浏览文件 @
112a8b1d
...
...
@@ -12,7 +12,7 @@ import org.springframework.context.annotation.Configuration;
import
java.util.List
;
/**
* Ela
* Ela
sticSearch HighLevelClient
*
* @author hxr
* @date 2021-03-05
...
...
youlai-common/common-elasticsearch/src/main/java/com/youlai/common/elasticsearch/service/ElasticSearchService.java
浏览文件 @
112a8b1d
...
...
@@ -21,6 +21,7 @@ import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInter
import
org.elasticsearch.search.aggregations.bucket.histogram.Histogram
;
import
org.elasticsearch.search.aggregations.bucket.histogram.ParsedDateHistogram
;
import
org.elasticsearch.search.builder.SearchSourceBuilder
;
import
org.elasticsearch.search.sort.SortBuilder
;
import
org.springframework.stereotype.Service
;
import
java.util.*
;
...
...
@@ -39,12 +40,9 @@ public class ElasticSearchService {
@SneakyThrows
public
long
count
(
QueryBuilder
queryBuilder
,
String
...
indices
)
{
// 构造搜索条件
SearchSourceBuilder
searchSourceBuilder
=
new
SearchSourceBuilder
();
searchSourceBuilder
.
query
(
queryBuilder
);
// 构造请求
CountRequest
countRequest
=
new
CountRequest
(
indices
);
countRequest
.
source
(
searchSource
Builder
);
countRequest
.
query
(
query
Builder
);
// 执行请求
CountResponse
countResponse
=
client
.
count
(
countRequest
,
RequestOptions
.
DEFAULT
);
long
count
=
countResponse
.
getCount
();
...
...
@@ -53,10 +51,11 @@ public class ElasticSearchService {
/**
* 日期统计
*
* @param queryBuilder 查询条件
* @param field 聚合字段,如:登录日志的 date 字段
* @param interval 统计时间间隔,如:1天、1周
* @param indices 索引名称
* @param field
聚合字段,如:登录日志的 date 字段
* @param interval
统计时间间隔,如:1天、1周
* @param indices
索引名称
* @return
*/
@SneakyThrows
...
...
@@ -107,11 +106,25 @@ public class ElasticSearchService {
@SneakyThrows
public
<
T
>
List
<
T
>
search
(
QueryBuilder
queryBuilder
,
Class
<
T
>
clazz
,
String
...
indices
)
{
List
<
T
>
list
=
this
.
search
(
queryBuilder
,
null
,
1
,
ESConstants
.
DEFAULT_PAGE_SIZE
,
clazz
,
indices
);
return
list
;
}
@SneakyThrows
public
<
T
>
List
<
T
>
search
(
QueryBuilder
queryBuilder
,
Integer
page
,
Integer
size
,
Class
<
T
>
clazz
,
String
...
indices
)
{
List
<
T
>
list
=
this
.
search
(
queryBuilder
,
null
,
1
,
ESConstants
.
DEFAULT_PAGE_SIZE
,
clazz
,
indices
);
return
list
;
}
@SneakyThrows
public
<
T
>
List
<
T
>
search
(
QueryBuilder
queryBuilder
,
SortBuilder
sortBuilder
,
Integer
page
,
Integer
size
,
Class
<
T
>
clazz
,
String
...
indices
)
{
// 构造SearchSourceBuilder
SearchSourceBuilder
searchSourceBuilder
=
new
SearchSourceBuilder
();
searchSourceBuilder
.
query
(
queryBuilder
);
searchSourceBuilder
.
from
(
0
);
searchSourceBuilder
.
size
(
ESConstants
.
DEFAULT_PAGE_SIZE
);
searchSourceBuilder
.
sort
(
sortBuilder
);
searchSourceBuilder
.
from
((
page
-
1
)
*
size
);
searchSourceBuilder
.
size
(
size
);
// 构造SearchRequest
SearchRequest
searchRequest
=
new
SearchRequest
(
indices
);
searchRequest
.
source
(
searchSourceBuilder
);
...
...
@@ -128,5 +141,4 @@ public class ElasticSearchService {
return
list
;
}
}
youlai-common/common-web/pom.xml
浏览文件 @
112a8b1d
...
...
@@ -28,12 +28,6 @@
<optional>
true
</optional>
</dependency>
<dependency>
<groupId>
com.github.dozermapper
</groupId>
<artifactId>
dozer-core
</artifactId>
<version>
6.2.0
</version>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-aop
</artifactId>
...
...
@@ -51,6 +45,18 @@
<artifactId>
logstash-logback-encoder
</artifactId>
</dependency>
<dependency>
<groupId>
org.lionsoul
</groupId>
<artifactId>
ip2region
</artifactId>
</dependency>
<dependency>
<groupId>
com.github.dozermapper
</groupId>
<artifactId>
dozer-core
</artifactId>
<version>
6.2.0
</version>
</dependency>
</dependencies>
</project>
youlai-common/common-web/src/main/java/com/youlai/common/web/aspect/LoginLogAspect.java
浏览文件 @
112a8b1d
package
com.youlai.common.web.aspect
;
import
cn.hutool.core.util.StrUtil
;
import
cn.hutool.extra.servlet.ServletUtil
;
import
cn.hutool.json.JSON
;
import
cn.hutool.json.JSONObject
;
import
cn.hutool.json.JSONUtil
;
import
com.youlai.common.constant.AuthConstants
;
import
com.youlai.common.web.pojo.domain.LoginLog
;
import
com.youlai.common.web.util.IpUtils
;
import
com.youlai.common.web.util.IPUtils
;
import
io.swagger.annotations.ApiOperation
;
import
lombok.AllArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
...
...
@@ -24,8 +21,9 @@ import org.springframework.web.context.request.RequestContextHolder;
import
org.springframework.web.context.request.ServletRequestAttributes
;
import
javax.servlet.http.HttpServletRequest
;
import
java.text.SimpleDateFormat
;
import
java.util.Date
;
import
java.time.Duration
;
import
java.time.LocalDateTime
;
import
java.time.format.DateTimeFormatter
;
/**
* @author hxr
...
...
@@ -44,47 +42,50 @@ public class LoginLogAspect {
@Around
(
"Log()"
)
public
Object
doAround
(
ProceedingJoinPoint
joinPoint
)
throws
Throwable
{
// 时间统计
Date
now
=
new
Date
();
long
startTime
=
now
.
getTime
();
Object
result
=
joinPoint
.
proceed
();
long
endTime
=
System
.
currentTimeMillis
();
long
elapsedTime
=
endTime
-
startTime
;
// 获取方法签名
MethodSignature
signature
=
(
MethodSignature
)
joinPoint
.
getSignature
();
String
description
=
signature
.
getMethod
().
getAnnotation
(
ApiOperation
.
class
).
value
();
LocalDateTime
startTime
=
LocalDateTime
.
now
();
Object
result
=
joinPoint
.
proceed
();
// 获取请求信息
ServletRequestAttributes
attributes
=
(
ServletRequestAttributes
)
RequestContextHolder
.
getRequestAttributes
();
HttpServletRequest
request
=
attributes
.
getRequest
();
// String clientIP = ServletUtil.getClientIP(request);
String
clientIP
=
IpUtils
.
getIpAddr
(
request
);
String
requestUrl
=
request
.
getRequestURL
().
toString
();
String
method
=
request
.
getMethod
();
// MDC 扩展logback字段,具体请看logback-spring.xml的自定义日志输出格式
MDC
.
put
(
"elapsedTime"
,
StrUtil
.
toString
(
elapsedTime
));
MDC
.
put
(
"description"
,
description
);
MDC
.
put
(
"clientIP"
,
clientIP
);
MDC
.
put
(
"url"
,
requestUrl
);
MDC
.
put
(
"method"
,
method
);
// 刷新token不记录
String
grantType
=
request
.
getParameter
(
AuthConstants
.
GRANT_TYPE_KEY
);
if
(
grantType
.
equals
(
AuthConstants
.
REFRESH_TOKEN
)){
return
result
;
}
String
username
=
request
.
getParameter
(
AuthConstants
.
USER_NAME_KEY
);
MDC
.
put
(
"username"
,
username
);
// 时间统计
LocalDateTime
endTime
=
LocalDateTime
.
now
();
long
elapsedTime
=
Duration
.
between
(
startTime
,
endTime
).
toMillis
();
// 请求耗时(毫秒)
SimpleDateFormat
simpleDateFormat
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
);
String
date
=
simpleDateFormat
.
format
(
now
);
MDC
.
put
(
"date"
,
date
);
// 获取接口描述信息
MethodSignature
signature
=
(
MethodSignature
)
joinPoint
.
getSignature
();
String
description
=
signature
.
getMethod
().
getAnnotation
(
ApiOperation
.
class
).
value
();
// 方法描述
String
username
=
request
.
getParameter
(
AuthConstants
.
USER_NAME_KEY
);
// 登录用户名
String
date
=
startTime
.
format
(
DateTimeFormatter
.
ofPattern
(
"yyyy-MM-dd"
));
// 索引名需要,因为默认生成索引的date时区不一致
// 获取
登录结果
String
accessT
oken
=
Strings
.
EMPTY
;
// 获取
token
String
t
oken
=
Strings
.
EMPTY
;
if
(
request
!=
null
)
{
JSONObject
jsonObject
=
JSONUtil
.
parseObj
(
result
);
accessT
oken
=
jsonObject
.
getStr
(
"value"
);
t
oken
=
jsonObject
.
getStr
(
"value"
);
}
MDC
.
put
(
"accessToken"
,
accessToken
);
log
.
info
(
"{} 登录,耗费时间 {} 毫秒"
,
username
,
elapsedTime
);
// 收集日志这里必须打印一条日志,内容随便
String
clientIP
=
IPUtils
.
getClientIP
(
request
);
// 客户端请求IP(注意:如果使用Nginx代理需配置)
String
region
=
IPUtils
.
ip2region
(
clientIP
);
// IP对应的城市信息
// MDC 扩展logback字段,具体请看logback-spring.xml的自定义日志输出格式
MDC
.
put
(
"elapsedTime"
,
StrUtil
.
toString
(
elapsedTime
));
MDC
.
put
(
"description"
,
description
);
MDC
.
put
(
"region"
,
region
);
MDC
.
put
(
"username"
,
username
);
MDC
.
put
(
"date"
,
date
);
MDC
.
put
(
"token"
,
token
);
MDC
.
put
(
"clientIP"
,
clientIP
);
log
.
info
(
"{} 登录,耗费时间 {} 毫秒"
,
username
,
elapsedTime
);
// 收集日志这里必须打印一条日志,内容随便吧,记录在message字段,具体看logback-spring.xml文件
return
result
;
}
}
youlai-common/common-web/src/main/java/com/youlai/common/web/util/I
p
Utils.java
→
youlai-common/common-web/src/main/java/com/youlai/common/web/util/I
P
Utils.java
浏览文件 @
112a8b1d
...
...
@@ -2,20 +2,29 @@ package com.youlai.common.web.util;
import
cn.hutool.core.util.StrUtil
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.logging.log4j.util.Strings
;
import
org.lionsoul.ip2region.DataBlock
;
import
org.lionsoul.ip2region.DbConfig
;
import
org.lionsoul.ip2region.DbSearcher
;
import
org.lionsoul.ip2region.Util
;
import
javax.servlet.http.HttpServletRequest
;
import
java.io.File
;
import
java.lang.reflect.Method
;
import
java.net.InetAddress
;
import
java.net.UnknownHostException
;
@Slf4j
public
class
IpUtils
{
public
class
IPUtils
{
private
static
String
LOCAL_IP
=
"127.0.0.1"
;
/**
* 获取IP地址
* 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
* 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
*/
public
static
String
get
IpAddr
(
HttpServletRequest
request
)
{
public
static
String
get
ClientIP
(
HttpServletRequest
request
)
{
String
ip
=
null
;
try
{
if
(
request
==
null
)
{
...
...
@@ -46,10 +55,8 @@ public class IpUtils {
}
//使用代理,则获取第一个IP地址
if
(
StrUtil
.
isEmpty
(
ip
)
&&
ip
.
length
()
>
15
)
{
if
(
ip
.
indexOf
(
","
)
>
0
)
{
ip
=
ip
.
substring
(
0
,
ip
.
indexOf
(
","
));
}
if
(
StrUtil
.
isNotBlank
(
ip
)
&&
ip
.
indexOf
(
","
)
>
0
)
{
ip
=
ip
.
substring
(
0
,
ip
.
indexOf
(
","
));
}
return
ip
;
...
...
@@ -71,4 +78,43 @@ public class IpUtils {
}
return
null
;
}
/**
* 解析IP获取城市区域信息
*
* @param ip
* @return
*/
public
static
String
ip2region
(
String
ip
)
{
if
(
Util
.
isIpAddress
(
ip
)
==
false
)
{
return
Strings
.
EMPTY
;
}
if
(
LOCAL_IP
.
equals
(
ip
)){
return
"本地访问"
;
}
String
filePath
=
IPUtils
.
class
.
getResource
(
"/data/ip2region.db"
).
getPath
();
File
file
=
new
File
(
filePath
);
if
(
file
.
exists
()
==
false
)
{
return
Strings
.
EMPTY
;
}
try
{
DbConfig
config
=
new
DbConfig
();
DbSearcher
searcher
=
new
DbSearcher
(
config
,
filePath
);
Method
method
=
searcher
.
getClass
().
getMethod
(
"btreeSearch"
,
String
.
class
);
DataBlock
dataBlock
=
(
DataBlock
)
method
.
invoke
(
searcher
,
ip
);
return
dataBlock
.
getRegion
();
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
return
Strings
.
EMPTY
;
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录