新增:服务器白名单校验功能

This commit is contained in:
gxwebsoft
2024-03-26 19:04:16 +08:00
parent 294306091a
commit 3b46e5ccc8
5 changed files with 107 additions and 52 deletions

View File

@@ -4,6 +4,8 @@ import cn.hutool.core.util.StrUtil;
import com.gxwebsoft.common.core.Constants;
import com.gxwebsoft.common.core.config.ConfigProperties;
import com.gxwebsoft.common.core.utils.CommonUtil;
import com.gxwebsoft.common.core.utils.RedisUtil;
import com.gxwebsoft.common.core.utils.SignCheckUtil;
import com.gxwebsoft.common.system.entity.LoginRecord;
import com.gxwebsoft.common.system.entity.Menu;
import com.gxwebsoft.common.system.entity.User;
@@ -35,51 +37,63 @@ import java.util.stream.Collectors;
*/
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Resource
private ConfigProperties configProperties;
@Resource
private UserService userService;
@Resource
private LoginRecordService loginRecordService;
@Resource
private ConfigProperties configProperties;
@Resource
private UserService userService;
@Resource
private LoginRecordService loginRecordService;
@Resource
private RedisUtil redisUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
String access_token = JwtUtil.getAccessToken(request);
if (StrUtil.isNotBlank(access_token)) {
try {
// 解析token
Claims claims = JwtUtil.parseToken(access_token, configProperties.getTokenKey());
JwtSubject jwtSubject = JwtUtil.getJwtSubject(claims);
User user = userService.getByUsername(jwtSubject.getUsername(), jwtSubject.getTenantId());
if (user == null) {
throw new UsernameNotFoundException("Username not found");
}
List<Menu> authorities = user.getAuthorities().stream()
.filter(m -> StrUtil.isNotBlank(m.getAuthority())).collect(Collectors.toList());
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
user, null, authorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
// token将要过期签发新token, 防止突然退出登录
long expiration = (claims.getExpiration().getTime() - new Date().getTime()) / 1000 / 60;
if (expiration < configProperties.getTokenRefreshTime()) {
String token = JwtUtil.buildToken(jwtSubject, configProperties.getTokenExpireTime(),
configProperties.getTokenKey());
response.addHeader(Constants.TOKEN_HEADER_NAME, token);
loginRecordService.saveAsync(user.getUsername(), LoginRecord.TYPE_REFRESH, null,
user.getTenantId(), request);
}
} catch (ExpiredJwtException e) {
CommonUtil.responseError(response, Constants.TOKEN_EXPIRED_CODE, Constants.TOKEN_EXPIRED_MSG,
e.getMessage());
return;
} catch (Exception e) {
CommonUtil.responseError(response, Constants.BAD_CREDENTIALS_CODE, Constants.BAD_CREDENTIALS_MSG,
e.toString());
return;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
String access_token = JwtUtil.getAccessToken(request);
if (StrUtil.isNotBlank(access_token)) {
try {
// 解析token
Claims claims = JwtUtil.parseToken(access_token, configProperties.getTokenKey());
JwtSubject jwtSubject = JwtUtil.getJwtSubject(claims);
// 校验服务器白名单
final SignCheckUtil checkUtil = new SignCheckUtil();
String key = "WhiteDomain:" + jwtSubject.getTenantId();
List<String> whiteDomains = redisUtil.get(key, List.class);
if (!checkUtil.checkWhiteDomains(whiteDomains, request.getServerName())) {
throw new UsernameNotFoundException("The requested domain name is not on the whitelist");
}
chain.doFilter(request, response);
User user = userService.getByUsername(jwtSubject.getUsername(), jwtSubject.getTenantId());
if (user == null) {
throw new UsernameNotFoundException("Username not found");
}
List<Menu> authorities = user.getAuthorities().stream()
.filter(m -> StrUtil.isNotBlank(m.getAuthority())).collect(Collectors.toList());
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
user, null, authorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
// token将要过期签发新token, 防止突然退出登录
long expiration = (claims.getExpiration().getTime() - new Date().getTime()) / 1000 / 60;
if (expiration < configProperties.getTokenRefreshTime()) {
String token = JwtUtil.buildToken(jwtSubject, configProperties.getTokenExpireTime(),
configProperties.getTokenKey());
response.addHeader(Constants.TOKEN_HEADER_NAME, token);
loginRecordService.saveAsync(user.getUsername(), LoginRecord.TYPE_REFRESH, null,
user.getTenantId(), request);
}
} catch (ExpiredJwtException e) {
CommonUtil.responseError(response, Constants.TOKEN_EXPIRED_CODE, Constants.TOKEN_EXPIRED_MSG,
e.getMessage());
return;
} catch (Exception e) {
CommonUtil.responseError(response, Constants.BAD_CREDENTIALS_CODE, Constants.BAD_CREDENTIALS_MSG,
e.toString());
return;
}
}
chain.doFilter(request, response);
}
}

View File

@@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSONObject;
import com.gxwebsoft.common.system.entity.KVEntity;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Resource;
import java.util.*;
/**
@@ -169,4 +170,24 @@ public class SignCheckUtil {
return sign.equals(getWXSignString(params, key));
}
/**
* 白名单校验
* @param domainName abc.com
* @return true
*/
public boolean checkWhiteDomains(List<String> whiteDomains, String domainName) {
if(whiteDomains == null){
return true;
}
if (whiteDomains.isEmpty()) {
return true;
}
for(String item: whiteDomains){
if(Objects.equals(item, domainName)){
return true;
}
}
return false;
}
}

View File

@@ -32,8 +32,6 @@ public class BaseController {
@Resource
private HttpServletRequest request;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private UserService userService;
@Resource
private CompanyService companyService;
@@ -222,6 +220,8 @@ public class BaseController {
return request.getParameter("sign");
}
/**
* 根据账号|手机号码|邮箱查找用户ID
*

View File

@@ -23,6 +23,7 @@ import com.gxwebsoft.common.core.security.JwtUtil;
import com.gxwebsoft.common.core.utils.CacheClient;
import com.gxwebsoft.common.core.utils.CommonUtil;
import com.gxwebsoft.common.core.utils.RedisUtil;
import com.gxwebsoft.common.core.utils.SignCheckUtil;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.core.web.ExistenceParam;
@@ -39,20 +40,19 @@ import com.wf.captcha.SpecCaptcha;
import io.jsonwebtoken.Claims;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import net.sf.jsqlparser.expression.LongValue;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
@@ -155,7 +155,7 @@ public class MainController extends BaseController {
@ApiOperation("获取当前租户信息")
@GetMapping("/auth/tenant")
public ApiResult<?> tenant() {
public ApiResult<?> tenant(HttpServletRequest request) {
Integer tenantId = getTenantId();
if (tenantId == null) {
return fail("缺少参数tenantId",null);
@@ -167,7 +167,7 @@ public class MainController extends BaseController {
// 企业信息
Company company = companyService.getByTenantIdRel(tenantId);
if(company == null){
return fail("租户不存在或已过期",null);
return fail("企业不存在",null);
}
company.setBusinessEntity(null);
company.setPhone(null);

View File

@@ -1,5 +1,7 @@
package com.gxwebsoft.common.system.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gxwebsoft.common.core.utils.RedisUtil;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.common.system.service.WhiteDomainService;
@@ -17,6 +19,7 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
/**
* 服务器白名单控制器
@@ -26,10 +29,12 @@ import java.util.List;
*/
@Api(tags = "服务器白名单管理")
@RestController
@RequestMapping("/api/common.system/white-domain")
@RequestMapping("/api/system/white-domain")
public class WhiteDomainController extends BaseController {
@Resource
private WhiteDomainService whiteDomainService;
@Resource
private RedisUtil redisUtil;
@PreAuthorize("hasAuthority('sys:whiteDomain:list')")
@ApiOperation("分页查询服务器白名单")
@@ -60,12 +65,18 @@ public class WhiteDomainController extends BaseController {
@ApiOperation("添加服务器白名单")
@PostMapping()
public ApiResult<?> save(@RequestBody WhiteDomain whiteDomain) {
String key = "WhiteDomain:";
// 记录当前登录用户id
User loginUser = getLoginUser();
if (loginUser != null) {
key = key + loginUser.getTenantId();
whiteDomain.setUserId(loginUser.getUserId());
}
if (whiteDomainService.save(whiteDomain)) {
// 重写缓存
final List<WhiteDomain> list = whiteDomainService.list();
final List<String> collect = list.stream().map(WhiteDomain::getDomain).collect(Collectors.toList());
redisUtil.set(key,collect);
return success("添加成功");
}
return fail("添加失败");
@@ -88,6 +99,15 @@ public class WhiteDomainController extends BaseController {
@DeleteMapping("/{id}")
public ApiResult<?> remove(@PathVariable("id") Integer id) {
if (whiteDomainService.removeById(id)) {
// 重写缓存
String key = "WhiteDomain:";
User loginUser = getLoginUser();
if (loginUser != null) {
key = key + loginUser.getTenantId();
}
final List<WhiteDomain> list = whiteDomainService.list();
final List<String> collect = list.stream().map(WhiteDomain::getDomain).collect(Collectors.toList());
redisUtil.set(key,collect);
return success("删除成功");
}
return fail("删除失败");