From f07aa9088506bb6f680b35abbf915292f849cbb1 Mon Sep 17 00:00:00 2001 From: huangfeng Date: Tue, 27 Feb 2024 16:16:14 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E7=99=BB=E5=85=A5=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/SysUserSession.java | 2 + .../filter/AbstractAuthorizationFilter.java | 35 ++++++++ .../filter/UrlAuthFilter.java | 69 ++++++++++++++++ .../filter/UserContextHolder.java | 23 ++++++ .../filter/UserInfoFilter.java | 79 +++++++++++++++++++ xymanager_service/pom.xml | 15 ++++ .../config/SecurityConfig.java | 66 ++++++++++++++++ .../impl/LoginServiceImpl.java | 22 ++++++ .../impl/SysUserServiceImpl.java | 4 +- .../service/SysUserService.java | 2 +- 10 files changed, 314 insertions(+), 3 deletions(-) create mode 100644 xymanager_framework/src/main/java/com/shxy/xymanager_framework/filter/AbstractAuthorizationFilter.java create mode 100644 xymanager_framework/src/main/java/com/shxy/xymanager_framework/filter/UrlAuthFilter.java create mode 100644 xymanager_framework/src/main/java/com/shxy/xymanager_framework/filter/UserContextHolder.java create mode 100644 xymanager_framework/src/main/java/com/shxy/xymanager_framework/filter/UserInfoFilter.java create mode 100644 xymanager_service/src/main/java/com/shxy/xymanager_service/config/SecurityConfig.java diff --git a/xymanager_common/src/main/java/com/shxy/xymanager_common/entity/SysUserSession.java b/xymanager_common/src/main/java/com/shxy/xymanager_common/entity/SysUserSession.java index 0e70163..6c427c4 100644 --- a/xymanager_common/src/main/java/com/shxy/xymanager_common/entity/SysUserSession.java +++ b/xymanager_common/src/main/java/com/shxy/xymanager_common/entity/SysUserSession.java @@ -12,6 +12,8 @@ public class SysUserSession implements Serializable { private String sessionId; + private String token; + private String userName; private Integer role; diff --git a/xymanager_framework/src/main/java/com/shxy/xymanager_framework/filter/AbstractAuthorizationFilter.java b/xymanager_framework/src/main/java/com/shxy/xymanager_framework/filter/AbstractAuthorizationFilter.java new file mode 100644 index 0000000..1cc65bc --- /dev/null +++ b/xymanager_framework/src/main/java/com/shxy/xymanager_framework/filter/AbstractAuthorizationFilter.java @@ -0,0 +1,35 @@ +package com.shxy.xymanager_framework.filter; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.shxy.xymanager_common.base.ResponseReult; +import com.shxy.xymanager_common.util.http.HttpStatus; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +public abstract class AbstractAuthorizationFilter extends OncePerRequestFilter { + + + protected void writeJsonResult(HttpServletRequest request, HttpServletResponse response, + ResponseReult result) throws IOException, ServletException { + ObjectMapper mapper = new ObjectMapper(); + response.setContentType("application/json;charset=utf-8"); + response.setStatus(HttpServletResponse.SC_OK); + PrintWriter out = response.getWriter(); + out.write(mapper.writeValueAsString(result)); + out.flush(); + out.close(); + } + + protected void writeException(HttpServletRequest request, HttpServletResponse response, + Exception ex) throws IOException, ServletException { + + ResponseReult result = ResponseReult.error(HttpStatus.HTTP_UNAUTHORIZED, ex.getMessage()); + writeJsonResult(request, response, result); + } +} diff --git a/xymanager_framework/src/main/java/com/shxy/xymanager_framework/filter/UrlAuthFilter.java b/xymanager_framework/src/main/java/com/shxy/xymanager_framework/filter/UrlAuthFilter.java new file mode 100644 index 0000000..ff0addc --- /dev/null +++ b/xymanager_framework/src/main/java/com/shxy/xymanager_framework/filter/UrlAuthFilter.java @@ -0,0 +1,69 @@ +package com.shxy.xymanager_framework.filter; + + +import com.shxy.xymanager_common.bean.SysUser; +import com.shxy.xymanager_service.config.SecurityConfig; +import com.shxy.xymanager_service.service.SysUserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.AntPathMatcher; +import org.springframework.util.PathMatcher; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Arrays; + +@Order(2) +@Component +@Slf4j +public class UrlAuthFilter extends AbstractAuthorizationFilter { + + SecurityConfig config; + SysUserService userService; + + public UrlAuthFilter(SecurityConfig config, SysUserService userService) { + this.config = config; + this.userService = userService; + } + + PathMatcher pathMatcher = new AntPathMatcher(); + + @Override + protected void doFilterInternal( + HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + if (!config.getUrlEnable()) { + filterChain.doFilter(request, response); + return; + } + + String path = request.getRequestURI(); + + int suffixIdx = path.lastIndexOf("."); + if (suffixIdx > -1 && Arrays.stream(config.getResourceSuffix().toArray()) + .anyMatch(a -> a.equals(path.substring(suffixIdx)))) { + filterChain.doFilter(request, response); + return; + } + + for (String white : config.getUrlWhiteList()) { + if (pathMatcher.match(white, path)) { + filterChain.doFilter(request, response); + return; + } + } + + SysUser user = UserContextHolder.currentUserInfo(); + if (user == null) { + writeException(request, response, new Exception("用户未登录或用户登录已过期")); + } else { + filterChain.doFilter(request, response); + } + } + +} \ No newline at end of file diff --git a/xymanager_framework/src/main/java/com/shxy/xymanager_framework/filter/UserContextHolder.java b/xymanager_framework/src/main/java/com/shxy/xymanager_framework/filter/UserContextHolder.java new file mode 100644 index 0000000..17bb939 --- /dev/null +++ b/xymanager_framework/src/main/java/com/shxy/xymanager_framework/filter/UserContextHolder.java @@ -0,0 +1,23 @@ +package com.shxy.xymanager_framework.filter; + +import com.shxy.xymanager_common.bean.SysUser; +import org.springframework.core.NamedInheritableThreadLocal; + +public class UserContextHolder { + private static final ThreadLocal inheritableRequestAttributesHolder = new NamedInheritableThreadLocal("userId context"); + + public UserContextHolder() { + } + + public static void setCurrentUserInfo(SysUser userInfo) { + inheritableRequestAttributesHolder.set(userInfo); + } + + public static SysUser currentUserInfo() { + return inheritableRequestAttributesHolder.get(); + } + + public static void reset() { + inheritableRequestAttributesHolder.remove(); + } +} diff --git a/xymanager_framework/src/main/java/com/shxy/xymanager_framework/filter/UserInfoFilter.java b/xymanager_framework/src/main/java/com/shxy/xymanager_framework/filter/UserInfoFilter.java new file mode 100644 index 0000000..30f39c7 --- /dev/null +++ b/xymanager_framework/src/main/java/com/shxy/xymanager_framework/filter/UserInfoFilter.java @@ -0,0 +1,79 @@ +package com.shxy.xymanager_framework.filter; + +import com.shxy.xymanager_common.bean.SysUser; +import com.shxy.xymanager_common.exception.CustomException; +import com.shxy.xymanager_service.config.SecurityConfig; +import com.shxy.xymanager_service.service.SysUserService; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.crypto.SecretKey; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +@Order(1) +@Slf4j +@Component +public class UserInfoFilter extends AbstractAuthorizationFilter { + + SecurityConfig config; + SysUserService userService; + + public UserInfoFilter(SecurityConfig config, SysUserService userService) { + this.config = config; + this.userService = userService; + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + boolean valid = false; + try { + valid = initContextHolders(request); + } catch (CustomException ex) { + log.error("用户登录信息出错!", ex); + writeException(request, response, ex); + } + if (valid) { + filterChain.doFilter(request, response); + } + UserContextHolder.reset(); + } + + private boolean initContextHolders(HttpServletRequest request) throws CustomException { + + String token = request.getHeader(config.getJwtHeader()); + if (!StringUtils.isBlank(token)) { + SecretKey key = Keys.hmacShaKeyFor(config.getJwtPwd().getBytes(StandardCharsets.UTF_8)); + try { + token = token.replace(config.getJwtPrefix() + " ", ""); + Claims claims = Jwts.parserBuilder() + .setSigningKey(key) + .build() + .parseClaimsJws(token) + .getBody(); + String userId = claims.getSubject(); + String jwtId = claims.getId(); + + if (!StringUtils.isBlank(userId)) { + SysUser user = userService.selectUserById(Integer.parseInt(userId)); + UserContextHolder.setCurrentUserInfo(user); + } + + } catch (JwtException ex) { + log.error(ex.getMessage(), ex); + throw new CustomException("用户未登录或用户登录已过期"); + } + } + return true; + } +} diff --git a/xymanager_service/pom.xml b/xymanager_service/pom.xml index 49807ec..d60f44e 100644 --- a/xymanager_service/pom.xml +++ b/xymanager_service/pom.xml @@ -15,6 +15,21 @@ + + io.jsonwebtoken + jjwt-api + 0.11.5 + + + io.jsonwebtoken + jjwt-impl + 0.11.5 + + + io.jsonwebtoken + jjwt-jackson + 0.11.5 + org.springframework spring-beans diff --git a/xymanager_service/src/main/java/com/shxy/xymanager_service/config/SecurityConfig.java b/xymanager_service/src/main/java/com/shxy/xymanager_service/config/SecurityConfig.java new file mode 100644 index 0000000..33abd2a --- /dev/null +++ b/xymanager_service/src/main/java/com/shxy/xymanager_service/config/SecurityConfig.java @@ -0,0 +1,66 @@ +package com.shxy.xymanager_service.config; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.PostConstruct; +import java.util.List; +import java.util.Set; + + +@Configuration +@Data +@Slf4j +public class SecurityConfig { + + private String jwtPwd = "x11d11ddf@!dddd12efwefwefwd1111ff1111qefeffeefffdfdfdfa1d"; + + private String jwtHeader = "Authorization"; + + private String jwtPrefix = "Bearer"; + + // default 24 hours + private Integer jwtExpiration = 24 * 60 * 60; + + private List urlWhiteList = Lists.newArrayList(); + + + /** + * 是否开启权限认证 + */ + private Boolean urlEnable = true; + /** + * 系统用户默认密码 + */ + private String defaultPwd = "Aa12345678"; + /** + * 默认的静态资源过滤 + */ + private String staticResource = ".jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.svg"; + + private Set resourceSuffix = Sets.newHashSet(); + + private List swagger = Lists.newArrayList("/swagger**", "/webjars/**", + "/v2/api-docs/**", "/v3/api-docs/**", "/swagger-resources/**"); + + @PostConstruct + private void init() { + if (StringUtils.isNotBlank(staticResource)) { + this.resourceSuffix = Sets.newHashSet(staticResource.split(",")); + } + urlWhiteList.addAll(swagger); + urlWhiteList.add("/api/login"); + urlWhiteList.add("/login"); + urlWhiteList.add("/doc.html"); + urlWhiteList.add("/error"); + urlWhiteList.add("/test/**"); + urlWhiteList.add("/getPhotoListForOpen"); + urlWhiteList.add("/ctrlCmaDeviceCapture"); + urlWhiteList.add("/cmaDeviceStatus"); + urlWhiteList.add("/cmaUserLogin"); + } +} diff --git a/xymanager_service/src/main/java/com/shxy/xymanager_service/impl/LoginServiceImpl.java b/xymanager_service/src/main/java/com/shxy/xymanager_service/impl/LoginServiceImpl.java index 40c4b6c..38fc13b 100644 --- a/xymanager_service/src/main/java/com/shxy/xymanager_service/impl/LoginServiceImpl.java +++ b/xymanager_service/src/main/java/com/shxy/xymanager_service/impl/LoginServiceImpl.java @@ -13,14 +13,20 @@ import com.shxy.xymanager_common.util.MyDateUtils; import com.shxy.xymanager_common.util.RsaUtils; import com.shxy.xymanager_common.util.StringUtils; import com.shxy.xymanager_dao.dao.SysUserMapperDao; +import com.shxy.xymanager_service.config.SecurityConfig; import com.shxy.xymanager_service.service.LoginService; import com.shxy.xymanager_service.service.SysUserService; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import javax.crypto.SecretKey; import java.math.BigInteger; +import java.nio.charset.StandardCharsets; import java.util.Date; +import java.util.UUID; /** * 装置通道实现层 @@ -29,6 +35,8 @@ import java.util.Date; @Slf4j public class LoginServiceImpl implements LoginService { + @Autowired + SecurityConfig config; @Autowired private SysUserService sysUserService; @@ -46,6 +54,8 @@ public class LoginServiceImpl implements LoginService { try { SysUserSession user = getLoginUser(sysUser); user.setSessionId(sessionId); + String token = this.generate(user.getId()); + user.setToken(token); // sysUserMapperDao.insertUserSession(user); Date date = new Date(); sysUserMapperDao.insertOrUpdate(user, date,date); @@ -58,6 +68,18 @@ public class LoginServiceImpl implements LoginService { return Asserts.error("登录失败"); } + private String generate(Integer userId) { + SecretKey key = Keys.hmacShaKeyFor(config.getJwtPwd().getBytes(StandardCharsets.UTF_8)); + String uuid = UuidUtils.getUUID(); + String jws = Jwts.builder() + .setSubject(String.valueOf(userId)) + .setExpiration(new Date(new Date().getTime() + config.getJwtExpiration() * 1000)) + .signWith(key) + .setId(uuid) + .compact(); + return jws; + } + /** * 用户登录校验 * diff --git a/xymanager_service/src/main/java/com/shxy/xymanager_service/impl/SysUserServiceImpl.java b/xymanager_service/src/main/java/com/shxy/xymanager_service/impl/SysUserServiceImpl.java index 7d36a45..76a96f4 100644 --- a/xymanager_service/src/main/java/com/shxy/xymanager_service/impl/SysUserServiceImpl.java +++ b/xymanager_service/src/main/java/com/shxy/xymanager_service/impl/SysUserServiceImpl.java @@ -78,8 +78,8 @@ public class SysUserServiceImpl implements SysUserService { } @Override - public SysUser selectUserById(Long userId) { - return sysUserMapperDao.selectUserById(userId); + public SysUser selectUserById(Integer userId) { + return sysUserMapperDao.selectByPrimaryKey(userId); } @Override diff --git a/xymanager_service/src/main/java/com/shxy/xymanager_service/service/SysUserService.java b/xymanager_service/src/main/java/com/shxy/xymanager_service/service/SysUserService.java index c6958d5..efc26aa 100644 --- a/xymanager_service/src/main/java/com/shxy/xymanager_service/service/SysUserService.java +++ b/xymanager_service/src/main/java/com/shxy/xymanager_service/service/SysUserService.java @@ -33,7 +33,7 @@ public interface SysUserService { * @param userId 用户ID * @return 用户对象信息 */ - SysUser selectUserById(Long userId); + SysUser selectUserById(Integer userId); ServiceBody addUser(SysUserVo vo);