mirror of
https://gitee.com/youlaitech/youlai-mall.git
synced 2024-12-22 20:54:26 +08:00
feat:会话强制下线
This commit is contained in:
parent
b01367fb2a
commit
112a8b1d19
9
pom.xml
9
pom.xml
@ -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</redisson.version>
|
||||
<ip2region.version>1.7.2</ip2region.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>
|
||||
|
||||
|
@ -0,0 +1,30 @@
|
||||
package com.youlai.admin.pojo.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author hxr
|
||||
* @date 2021-03-09
|
||||
*/
|
||||
@Data
|
||||
public class LoginRecord {
|
||||
|
||||
private String _id;
|
||||
|
||||
private String description;
|
||||
|
||||
private String clientIP;
|
||||
|
||||
private long elapsedTime;
|
||||
|
||||
private Object message;
|
||||
|
||||
private String token;
|
||||
|
||||
private String username;
|
||||
|
||||
private String loginTime;
|
||||
|
||||
private String region;
|
||||
|
||||
}
|
@ -77,7 +77,10 @@
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.nimbusds</groupId>
|
||||
<artifactId>nimbus-jose-jwt</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -8,4 +8,7 @@ public interface ESConstants {
|
||||
|
||||
String INDEX_LOGIN_PREFIX = "youlai-auth-login-";
|
||||
|
||||
|
||||
String INDEX_LOGIN_PATTERN = "youlai-auth-login-*";
|
||||
|
||||
}
|
||||
|
@ -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.IpUtils;
|
||||
import com.youlai.common.web.util.IPUtils;
|
||||
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 = IpUtils.getIpAddr(request);
|
||||
String clientIP = IPUtils.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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,92 @@
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
@ -1,16 +1,11 @@
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Ela
|
||||
* ElasticSearch HighLevelClient
|
||||
*
|
||||
* @author hxr
|
||||
* @date 2021-03-05
|
||||
|
@ -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(searchSourceBuilder);
|
||||
countRequest.query(queryBuilder);
|
||||
// 执行请求
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -1,13 +1,10 @@
|
||||
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();
|
||||
|
||||
// 刷新token不记录
|
||||
String grantType=request.getParameter(AuthConstants.GRANT_TYPE_KEY);
|
||||
if(grantType.equals(AuthConstants.REFRESH_TOKEN)){
|
||||
return result;
|
||||
}
|
||||
|
||||
// 时间统计
|
||||
LocalDateTime endTime = LocalDateTime.now();
|
||||
long elapsedTime = Duration.between(startTime, endTime).toMillis(); // 请求耗时(毫秒)
|
||||
|
||||
// 获取接口描述信息
|
||||
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时区不一致
|
||||
|
||||
// 获取token
|
||||
String token = Strings.EMPTY;
|
||||
if (request != null) {
|
||||
JSONObject jsonObject = JSONUtil.parseObj(result);
|
||||
token = jsonObject.getStr("value");
|
||||
}
|
||||
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("clientIP", clientIP);
|
||||
MDC.put("url", requestUrl);
|
||||
MDC.put("method", method);
|
||||
|
||||
String username = request.getParameter(AuthConstants.USER_NAME_KEY);
|
||||
MDC.put("region", region);
|
||||
MDC.put("username", username);
|
||||
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
String date = simpleDateFormat.format(now);
|
||||
MDC.put("date", date);
|
||||
MDC.put("token", token);
|
||||
MDC.put("clientIP", clientIP);
|
||||
|
||||
// 获取登录结果
|
||||
String accessToken = Strings.EMPTY;
|
||||
if (request != null) {
|
||||
JSONObject jsonObject = JSONUtil.parseObj(result);
|
||||
accessToken = jsonObject.getStr("value");
|
||||
}
|
||||
MDC.put("accessToken", accessToken);
|
||||
log.info("{} 登录,耗费时间 {} 毫秒", username, elapsedTime); // 收集日志这里必须打印一条日志,内容随便
|
||||
log.info("{} 登录,耗费时间 {} 毫秒", username, elapsedTime); // 收集日志这里必须打印一条日志,内容随便吧,记录在message字段,具体看logback-spring.xml文件
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
package com.youlai.common.web.pojo.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author haoxr
|
||||
* @Date 2021-03-01 16:45
|
||||
* @Version 1.0.0
|
||||
*/
|
||||
@Data
|
||||
public class LoginLog {
|
||||
|
||||
private String description;
|
||||
|
||||
private String clientIP;
|
||||
|
||||
private String url;
|
||||
|
||||
private String method;
|
||||
|
||||
private long elapsedTime;
|
||||
|
||||
private Object result;
|
||||
|
||||
}
|
@ -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 getIpAddr(HttpServletRequest request) {
|
||||
public static String getClientIP(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;
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user