diff --git a/pom.xml b/pom.xml index 934ffc78eddc1957b847bb90ffd5e8dbf8a10db6..78b018c4c121ee9dd9383d8fe1b82eef55b77dc9 100644 --- a/pom.xml +++ b/pom.xml @@ -46,9 +46,10 @@ 1.4.1 2.9.0 2.0.8 + 3.11.1 6.6 7.10.1 - 3.11.1 + 1.7.2 @@ -174,6 +175,12 @@ ${redisson.version} + + org.lionsoul + ip2region + ${ip2region.version} + + diff --git a/youlai-admin/admin-api/src/main/java/com/youlai/admin/pojo/domain/LoginRecord.java b/youlai-admin/admin-api/src/main/java/com/youlai/admin/pojo/domain/LoginRecord.java new file mode 100644 index 0000000000000000000000000000000000000000..2aba2188e56e5d2b5eeb660ed036d8ac5f720c6f --- /dev/null +++ b/youlai-admin/admin-api/src/main/java/com/youlai/admin/pojo/domain/LoginRecord.java @@ -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; + +} diff --git a/youlai-admin/admin-boot/pom.xml b/youlai-admin/admin-boot/pom.xml index 1d278068317a8b17907c5c80ce8598b5dc68d7c5..c7a8b246e7bc4e358da7b9055ebb326bdd726518 100644 --- a/youlai-admin/admin-boot/pom.xml +++ b/youlai-admin/admin-boot/pom.xml @@ -77,7 +77,10 @@ spring-boot-starter-web - + + com.nimbusds + nimbus-jose-jwt + diff --git a/youlai-admin/admin-boot/src/main/java/com/youlai/admin/common/constant/ESConstants.java b/youlai-admin/admin-boot/src/main/java/com/youlai/admin/common/constant/ESConstants.java index 7eaa506039b225b7e19df4d852ebf609aaee7c76..1d6416ed302113036304951037f2bb69d9253797 100644 --- a/youlai-admin/admin-boot/src/main/java/com/youlai/admin/common/constant/ESConstants.java +++ b/youlai-admin/admin-boot/src/main/java/com/youlai/admin/common/constant/ESConstants.java @@ -8,4 +8,7 @@ public interface ESConstants { String INDEX_LOGIN_PREFIX = "youlai-auth-login-"; + + String INDEX_LOGIN_PATTERN = "youlai-auth-login-*"; + } diff --git a/youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/DashboardController.java b/youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/DashboardController.java index 9d34dcb5d196470e56beac8b56fd3cd52ab46e27..b1d4ab8f5afa2eeec11d1f56d94544bd276d37f2 100644 --- a/youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/DashboardController.java +++ b/youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/DashboardController.java @@ -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 myCountMap = elasticSearchService.dateHistogram(boolQueryBuilder, "date", DateHistogramInterval.days(1), indices); @@ -97,4 +97,5 @@ public class DashboardController { return Result.success(map); } + } diff --git a/youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/LoginRecordController.java b/youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/LoginRecordController.java new file mode 100644 index 0000000000000000000000000000000000000000..98bec1597e5d9b388e5caef3630f31dc4dca1520 --- /dev/null +++ b/youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/LoginRecordController.java @@ -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 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); + } + + + + +} diff --git a/youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/TokenController.java b/youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/TokenController.java new file mode 100644 index 0000000000000000000000000000000000000000..f00b8b94c2c7a6047fe54a84e747040c7de73df7 --- /dev/null +++ b/youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/TokenController.java @@ -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(); + } + +} diff --git a/youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/UserController.java b/youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/UserController.java index d35949a48e10c6ff900ddda622c91610c97d8d1d..e58d0187a674a7b88214c2739ccc4eab7e5b2cba 100644 --- a/youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/UserController.java +++ b/youlai-admin/admin-boot/src/main/java/com/youlai/admin/controller/UserController.java @@ -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; diff --git a/youlai-admin/admin-boot/src/test/java/com/youlai/admin/ElasticSearchTests.java b/youlai-admin/admin-boot/src/test/java/com/youlai/admin/ElasticSearchTests.java index b7e091a3cbb6ce830ebcd2b14aa18b42547bbe66..ec2780b8d107262545ac185b7a449dd6746daae4 100644 --- a/youlai-admin/admin-boot/src/test/java/com/youlai/admin/ElasticSearchTests.java +++ b/youlai-admin/admin-boot/src/test/java/com/youlai/admin/ElasticSearchTests.java @@ -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 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 map = elasticSearchService.dateHistogram(null, "date",DateHistogramInterval.days(1),"youlai-auth-login-2021-03-07","youlai-auth-login-2021-03-08"); - log.info(map.toString()); - } } diff --git a/youlai-auth/src/main/java/com/youlai/auth/controller/LogoutController.java b/youlai-auth/src/main/java/com/youlai/auth/controller/LogoutController.java index f1ae1e2fdfc92abd186cf0255460c5239dd712c3..df29e7737e15dfd74755aa2020a8e71ff7f04733 100644 --- a/youlai-auth/src/main/java/com/youlai/auth/controller/LogoutController.java +++ b/youlai-auth/src/main/java/com/youlai/auth/controller/LogoutController.java @@ -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; diff --git a/youlai-common/common-core/src/main/java/com/youlai/common/constant/AuthConstants.java b/youlai-common/common-core/src/main/java/com/youlai/common/constant/AuthConstants.java index 8bdc47b5767d806d9dad6f172101f63ef352ad27..2ac37c13ad64ab39713919de22ebf4d1067bd589 100644 --- a/youlai-common/common-core/src/main/java/com/youlai/common/constant/AuthConstants.java +++ b/youlai-common/common-core/src/main/java/com/youlai/common/constant/AuthConstants.java @@ -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"; } diff --git a/youlai-common/common-elasticsearch/src/main/java/com/youlai/common/elasticsearch/config/RestHighLevelClientConfig.java b/youlai-common/common-elasticsearch/src/main/java/com/youlai/common/elasticsearch/config/RestHighLevelClientConfig.java index 4928282a3ca7e366d7a1411e383c7df2e9cdb2f7..11920088a62336dbbec6b0102003b7a9516b8c9b 100644 --- a/youlai-common/common-elasticsearch/src/main/java/com/youlai/common/elasticsearch/config/RestHighLevelClientConfig.java +++ b/youlai-common/common-elasticsearch/src/main/java/com/youlai/common/elasticsearch/config/RestHighLevelClientConfig.java @@ -12,7 +12,7 @@ import org.springframework.context.annotation.Configuration; import java.util.List; /** - * Ela + * ElasticSearch HighLevelClient * * @author hxr * @date 2021-03-05 diff --git a/youlai-common/common-elasticsearch/src/main/java/com/youlai/common/elasticsearch/service/ElasticSearchService.java b/youlai-common/common-elasticsearch/src/main/java/com/youlai/common/elasticsearch/service/ElasticSearchService.java index 37e83f219d42484aeb675f7eaaf164882b40f7ee..b22cdad1f538895a8601d578a78efaef36b49859 100644 --- a/youlai-common/common-elasticsearch/src/main/java/com/youlai/common/elasticsearch/service/ElasticSearchService.java +++ b/youlai-common/common-elasticsearch/src/main/java/com/youlai/common/elasticsearch/service/ElasticSearchService.java @@ -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 List search(QueryBuilder queryBuilder, Class clazz, String... indices) { + List list = this.search(queryBuilder, null, 1, ESConstants.DEFAULT_PAGE_SIZE, clazz, indices); + return list; + } + + + @SneakyThrows + public List search(QueryBuilder queryBuilder, Integer page, Integer size, Class clazz, String... indices) { + List list = this.search(queryBuilder, null, 1, ESConstants.DEFAULT_PAGE_SIZE, clazz, indices); + return list; + } + + @SneakyThrows + public List search(QueryBuilder queryBuilder, SortBuilder sortBuilder, Integer page, Integer size, Class 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; } - } diff --git a/youlai-common/common-web/pom.xml b/youlai-common/common-web/pom.xml index b63a2d40abc97aeefccfaa9a3d05695dd1cbf4e6..116430c8b6f73a83a270d00d5b0b084beeb1dd87 100644 --- a/youlai-common/common-web/pom.xml +++ b/youlai-common/common-web/pom.xml @@ -28,12 +28,6 @@ true - - com.github.dozermapper - dozer-core - 6.2.0 - - org.springframework.boot spring-boot-starter-aop @@ -51,6 +45,18 @@ logstash-logback-encoder + + org.lionsoul + ip2region + + + + + com.github.dozermapper + dozer-core + 6.2.0 + + diff --git a/youlai-common/common-web/src/main/java/com/youlai/common/web/aspect/LoginLogAspect.java b/youlai-common/common-web/src/main/java/com/youlai/common/web/aspect/LoginLogAspect.java index 15f986cb540bcfc3f1a85825bd0378bb8a89791e..e6e5e0c1d628889adc0e863dec9051f56a98e41e 100644 --- a/youlai-common/common-web/src/main/java/com/youlai/common/web/aspect/LoginLogAspect.java +++ b/youlai-common/common-web/src/main/java/com/youlai/common/web/aspect/LoginLogAspect.java @@ -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(); - // 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 accessToken = Strings.EMPTY; + // 获取token + String token = Strings.EMPTY; if (request != null) { JSONObject jsonObject = JSONUtil.parseObj(result); - accessToken = jsonObject.getStr("value"); + token = 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; } } diff --git a/youlai-common/common-web/src/main/java/com/youlai/common/web/pojo/domain/LoginLog.java b/youlai-common/common-web/src/main/java/com/youlai/common/web/pojo/domain/LoginLog.java deleted file mode 100644 index 7f1d07f6f8ec479b5f47406c26dcab4d479b1048..0000000000000000000000000000000000000000 --- a/youlai-common/common-web/src/main/java/com/youlai/common/web/pojo/domain/LoginLog.java +++ /dev/null @@ -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; - -} diff --git a/youlai-common/common-web/src/main/java/com/youlai/common/web/util/IpUtils.java b/youlai-common/common-web/src/main/java/com/youlai/common/web/util/IPUtils.java similarity index 59% rename from youlai-common/common-web/src/main/java/com/youlai/common/web/util/IpUtils.java rename to youlai-common/common-web/src/main/java/com/youlai/common/web/util/IPUtils.java index 41bba04f35c92fbfa0e9500d43a678a5d96eac0b..ca37484d36fbf760fdb9c1c2abab301156ce699b 100644 --- a/youlai-common/common-web/src/main/java/com/youlai/common/web/util/IpUtils.java +++ b/youlai-common/common-web/src/main/java/com/youlai/common/web/util/IPUtils.java @@ -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; + } + + }