1. 增加SpringSecurity支持

This commit is contained in:
黄昕 2024-03-07 16:26:47 +08:00
parent 566074ff21
commit 88f9efb212
77 changed files with 2038 additions and 85 deletions

73
cs-authentication/pom.xml Normal file
View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.cf.cs</groupId>
<artifactId>IntegrateService</artifactId>
<version>0.0.1-dev</version>
</parent>
<artifactId>cs-authentication</artifactId>
<name>cs-authentication</name>
<description>cs-authentication</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.casbin</groupId>
<artifactId>jcasbin</artifactId>
<version>1.50.0</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.12.3</version>
</dependency>
<dependency>
<groupId>com.cf.cs</groupId>
<artifactId>cs-crypto</artifactId>
<version>${cs-package.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.cf.cs</groupId>
<artifactId>cs-database</artifactId>
<version>${cs-package.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.cf.cs</groupId>
<artifactId>cs-protocol</artifactId>
<version>${cs-package.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,23 @@
package com.cf.cs.authentication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* The type Cs authentication application.
*
* @author xajhuang @163.com
*/
@SpringBootApplication
public class CsAuthenticationApplication {
/**
* The entry point of application.
*
* @param args the input arguments
*/
public static void main(String[] args) {
SpringApplication.run(CsAuthenticationApplication.class, args);
}
}

View File

@ -0,0 +1,133 @@
package com.cf.cs.authentication.configure;
import com.cf.cs.authentication.security.impl.CustomAuthorizationManager;
import com.cf.cs.authentication.security.impl.JwtAccessDeniedHandler;
import com.cf.cs.authentication.security.impl.JwtAuthenticationEntryPoint;
import com.cf.cs.authentication.security.impl.JwtAuthenticationFilter;
import com.cf.cs.authentication.security.impl.JwtCustomUsernamePassword;
import com.cf.cs.authentication.security.impl.JwtLogoutHandler;
import com.cf.cs.authentication.security.impl.JwtLogoutSuccessHandler;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
/**
* The type Security.
*
* @author xajhuang @163.com
*/
@Configuration
@EnableWebSecurity
@Slf4j
public class SecuritySecurity {
/**
* The User details service.
*/
@Resource
UserDetailsService userDetailsService;
@Resource
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Resource
private JwtAccessDeniedHandler jwtAccessDeniedHandler;
@Resource
private JwtLogoutSuccessHandler jwtLogoutSuccessHandler;
@Resource
private JwtLogoutHandler jwtLogoutHandler;
@Resource
private JwtAuthenticationFilter tokenFilter;
@Resource
private CustomAuthorizationManager customAuthorizationManager;
@Resource
private UserSecurityConfigure userSecurityConfigure;
/**
* Password encoder password encoder.
*
* @return the password encoder
*/
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* Filter chain security filter chain.
*
* @param http the http
* @return the security filter chain
* @throws Exception the exception
*/
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(resp -> {
// 配置文件中配置的白名单
userSecurityConfigure.getWhiteList().forEach(k -> resp.requestMatchers(k.getMethod(), k.getUrl()).permitAll());
resp.requestMatchers("/api/**").access(customAuthorizationManager);
})
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.formLogin(AbstractHttpConfigurer::disable)
.exceptionHandling((exceptions) -> exceptions.authenticationEntryPoint(jwtAuthenticationEntryPoint)
.accessDeniedHandler(jwtAccessDeniedHandler))
.logout(logout -> logout.logoutUrl("/api/logout")
.addLogoutHandler(jwtLogoutHandler)
.logoutSuccessHandler(jwtLogoutSuccessHandler)
.clearAuthentication(true)
)
.csrf(AbstractHttpConfigurer::disable);
http.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(tokenFilter, LogoutFilter.class);
http.addFilterAt(jwtCustomUsernamePassword(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
/**
* Jwt custom username password jwt custom username password.
*
* @return the jwt custom username password
*/
@Bean
public JwtCustomUsernamePassword jwtCustomUsernamePassword() {
JwtCustomUsernamePassword jwtCustomUsernamePassword = new JwtCustomUsernamePassword();
jwtCustomUsernamePassword.setAuthenticationManager(authenticationManager());
jwtCustomUsernamePassword.setFilterProcessesUrl("/api/login");
jwtCustomUsernamePassword.setSecurityContextRepository(new HttpSessionSecurityContextRepository());
return jwtCustomUsernamePassword;
}
/**
* Authentication manager.
*
* @return the authentication manager
*/
@Bean
AuthenticationManager authenticationManager() {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setUserDetailsService(userDetailsService);
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
return new ProviderManager(daoAuthenticationProvider);
}
}

View File

@ -0,0 +1,28 @@
package com.cf.cs.authentication.configure;
import com.cf.cs.authentication.pojo.po.UrlFilterItem;
import jakarta.annotation.PostConstruct;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.util.List;
/**
* The type User security configure.
*
* @author xajhuang @163.com
*/
@Configuration
@ConfigurationProperties(prefix = "security.ui")
@Data
@Slf4j
public class UserSecurityConfigure {
private List<UrlFilterItem> whiteList;
@PostConstruct
private void initGlobalValue() {
log.info("Current: writeList = [{}]", whiteList);
}
}

View File

@ -0,0 +1,54 @@
package com.cf.cs.authentication.exception;
import com.cf.cs.base.common.ErrorCode;
import lombok.Getter;
import lombok.Setter;
import org.springframework.security.core.AuthenticationException;
/**
* The type Common auth exception.
*
* @author xajhuang @163.com
*/
@Getter
@Setter
public class CommonAuthException extends AuthenticationException {
private ErrorCode err;
private String[] description;
/**
* Instantiates a new Common auth exception.
*
* @param err to err
*/
public CommonAuthException(ErrorCode err) {
super(err.getDescription());
this.err = err;
this.description = new String[] {err.getDescription()};
}
/**
* Instantiates a new Common auth exception.
*
* @param err to err
* @param readme the readme
*/
public CommonAuthException(ErrorCode err, String readme) {
super(readme);
this.err = err;
this.description = new String[] {readme};
}
/**
* Instantiates a new Common auth exception.
*
* @param err to err
* @param readme the readme
*/
public CommonAuthException(ErrorCode err, String[] readme) {
super(err.getDescription());
this.err = err;
this.description = readme;
}
}

View File

@ -1,4 +1,4 @@
package com.cf.cs.web.interceptor;
package com.cf.cs.authentication.interceptor;
import com.cf.cs.base.misc.ApiContextUtils;
import com.cf.cs.base.misc.HelperUtils;

View File

@ -1,4 +1,4 @@
package com.cf.cs.web.interceptor;
package com.cf.cs.authentication.interceptor;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;

View File

@ -0,0 +1,108 @@
package com.cf.cs.authentication.misc;
import com.cf.cs.authentication.pojo.po.AuthAccountUser;
import com.cf.cs.authentication.service.AuthUsersService;
import com.cf.cs.database.mapper.RoleMapper;
import com.cf.cs.database.pojo.entity.Role;
import com.cf.cs.database.service.RoleResourceService;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.casbin.jcasbin.main.Enforcer;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import static com.cf.cs.database.pojo.entity.table.RoleTableDef.ROLE;
/**
* The type Casbin authorize utils.
*
* @author xajhuang @163.com
*/
@Component
@Slf4j
public class CasbinAuthorizeUtils {
private static final ConcurrentHashMap<String, Enforcer> ENFORCER_POOL = new ConcurrentHashMap<>();
@Resource
private AuthUsersService authUsersService;
@Resource
private RoleResourceService roleResourceService;
@Resource
private RoleMapper roleMapper;
/**
* Init.
*/
@PostConstruct
public void init() {
roleMapper.selectAll().forEach(role -> {
if (!CasbinAuthorizeUtils.ENFORCER_POOL.containsKey(role.getName())) {
String model = Objects.requireNonNull(this.getClass().getResource("/casbin/model.conf")).getFile();
String policy = Objects.requireNonNull(this.getClass().getResource("/casbin/policy.csv")).getFile();
Enforcer e = new Enforcer(model, policy);
e.enableAutoSave(false);
List<Role> subRole = roleMapper.selectListByCondition(ROLE.ID.ge(role.getId()));
subRole.forEach(k -> {
e.addRoleForUser(role.getName(), k.getName());
log.trace("+++{} has {}", role.getName(), k.getName());
});
// 添加角色资源权限
roleResourceService.getRoleResourceByRoleId(role.getId()).forEach(k -> {
e.addPermissionForUser(role.getName(), k.getResources().getPath(), k.getResources().getHttpMethod(),
k.getAuthorize() ? "allow" : "deny");
log.trace("++++++[{}, {}, {}: {}]", role.getName(), k.getResources().getPath(),
k.getResources().getHttpMethod(), k.getAuthorize() ? "allow" : "deny");
});
// 缓存当前权限验证器
CasbinAuthorizeUtils.ENFORCER_POOL.put(role.getName(), e);
}
});
}
/**
* Casbin verify authorize boolean.
*
* @param userName the username
* @param url the url
* @param httpMethod the http method
* @return the boolean
*/
public boolean casbinVerifyAuthorize(String userName, String url, String httpMethod) {
AuthAccountUser user = authUsersService.getAuthAccountByUserName(userName);
if (user == null) {
return false;
}
// 角色被禁用
if (!user.getRole().getAvailable()) {
return false;
}
Enforcer e = CasbinAuthorizeUtils.ENFORCER_POOL.get(user.getRole().getName());
if (e != null) {
// 支持权限继承
for (String s : e.getImplicitRolesForUser(user.getRole().getName())) {
Enforcer se = CasbinAuthorizeUtils.ENFORCER_POOL.get(s);
if (s != null) {
if (se.enforce(s, url, httpMethod)) {
return true;
}
}
}
}
return false;
}
}

View File

@ -0,0 +1,142 @@
package com.cf.cs.authentication.misc;
import com.cf.cs.authentication.exception.CommonAuthException;
import com.cf.cs.base.common.ConstValue;
import com.cf.cs.base.common.ErrorCode;
import com.cf.cs.base.config.JwtConfigure;
import com.cf.cs.crypto.arithmetic.CryptoHelper;
import com.cf.cs.database.pojo.entity.User;
import com.cf.cs.database.service.UserDataBaseService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.MissingClaimException;
import io.jsonwebtoken.security.Keys;
import io.micrometer.common.util.StringUtils;
import jakarta.annotation.Resource;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
/**
* The type Jwt utils.
*
* @author xajhuang @163.com
*/
@Data
@Component
@Slf4j
public class JwtUtils {
@Resource
private JwtConfigure jwtConfigure;
@Resource
private UserDataBaseService userService;
/**
* Gets head value.
*
* @return the head value
*/
public String getHeadValue() {
return jwtConfigure.getHttpHead();
}
/**
* Gets token.
*
* @param uId the u id
* @return the token
*/
public String getToken(String uId) {
Date nowDate = new Date();
Date expireDate = new Date(nowDate.getTime() + 1000 * jwtConfigure.getExpireTime());
return Jwts.builder()
.header()
.add("typ", "JWT")
.and()
.signWith(Keys.hmacShaKeyFor(getSecretKey(jwtConfigure.getSecretKey())))
.expiration(expireDate)
.issuedAt(nowDate)
.id(uId)
.compact();
}
/**
* Parse token user.
*
* @param jwt the jwt
* @return the user
*/
public User parseToken(String jwt) {
try {
if (!jwt.startsWith(ConstValue.STRING_HTTP_AUTH_HEAD)) {
throw new CommonAuthException(ErrorCode.ERR_MISSAUTHHEAD);
}
jwt = jwt.replace(ConstValue.STRING_HTTP_AUTH_HEAD, "");
Claims claim = Jwts.parser()
.verifyWith(Keys.hmacShaKeyFor(getSecretKey(jwtConfigure.getSecretKey())))
.build()
.parseSignedClaims(jwt)
.getPayload();
if (isTokenExpired(claim)) {
throw new CommonAuthException(ErrorCode.ERR_TOKENTIMEOUT);
}
String uid = claim.getId();
if (StringUtils.isBlank(uid) || StringUtils.isEmpty(uid)) {
throw new CommonAuthException(ErrorCode.ERR_TOKENNOTFOUND);
}
// 获取用户的权限等信息
User user = userService.getAccountUserByUid(uid);
if (user == null) {
throw new CommonAuthException(ErrorCode.ERR_TOKENNOTFOUND);
}
return user;
} catch (MalformedJwtException e) {
throw new CommonAuthException(ErrorCode.ERR_TOKEN_KEY, "密钥算法或者密钥转换错误");
} catch (MissingClaimException e) {
throw new CommonAuthException(ErrorCode.ERR_TOKEN_KEY, "密钥缺少校验数据");
} catch (ExpiredJwtException e) {
throw new CommonAuthException(ErrorCode.ERR_TOKEN_KEY, "密钥已过期");
} catch (JwtException e) {
throw new CommonAuthException(ErrorCode.ERR_TOKEN_KEY, "密钥解析错误");
}
}
private byte[] getSecretKey(String base64Key) {
if (StringUtils.isBlank(base64Key)) {
throw new CommonAuthException(ErrorCode.ERR_TOKEN_KEY);
}
try {
return CryptoHelper.sha256Encryption(base64Key);
} catch (NoSuchAlgorithmException e) {
throw new CommonAuthException(ErrorCode.ERR_TOKEN_KEY);
}
}
/**
* Is token expired boolean.
*
* @param claims the claims
* @return the boolean
*/
public boolean isTokenExpired(Claims claims) {
return claims.getExpiration().before(new Date());
}
}

View File

@ -0,0 +1,76 @@
package com.cf.cs.authentication.misc;
import com.cf.cs.base.common.CommonEnumHandler;
import com.cf.cs.base.common.ErrorCode;
import com.cf.cs.base.misc.HelperUtils;
import com.cf.cs.database.service.OperationLogDataBaseService;
import com.cf.cs.protocol.pojo.po.BaseRespStatus;
import com.cf.cs.protocol.pojo.vo.ProtocolResp;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* The type Security response utils.
*
* @author xajhuang @163.com
*/
public class SecurityResponseUtils {
/**
* Authentication response.
*
* @param request the request
* @param response the response
* @param error the error
* @param readme the readme
* @param logService the log service
* @throws IOException the io exception
*/
public static void authenticationResponse(HttpServletRequest request,
HttpServletResponse response,
ErrorCode error,
String readme, OperationLogDataBaseService logService) throws IOException {
response.setContentType("application/json;charset=UTF-8");
ServletOutputStream outputStream = response.getOutputStream();
ProtocolResp<BaseRespStatus> ret = ProtocolResp.result(error);
if (logService != null) {
logService.securityOperationLog(request, ret, error, readme);
}
outputStream.write(HelperUtils.getJsonBytes(ret));
outputStream.flush();
outputStream.close();
}
/**
* Authentication response.
*
* @param <T> the type parameter
* @param request the request
* @param response the response
* @param rsp the rsp
* @param readme the readme
* @param logService the log service
* @throws IOException the io exception
*/
public static <T extends BaseRespStatus> void authenticationResponse(HttpServletRequest request,
HttpServletResponse response,
T rsp,
String readme, OperationLogDataBaseService logService) throws IOException {
response.setContentType("application/json;charset=UTF-8");
ServletOutputStream outputStream = response.getOutputStream();
ProtocolResp<BaseRespStatus> ret = ProtocolResp.result(ErrorCode.ERR_OK);
if (logService != null) {
logService.securityOperationLog(request, ret, CommonEnumHandler.codeOf(ErrorCode.class, rsp.getStatus()), readme);
}
outputStream.write(HelperUtils.getJsonBytes(ProtocolResp.result(rsp)));
outputStream.flush();
outputStream.close();
}
}

View File

@ -0,0 +1,66 @@
package com.cf.cs.authentication.pojo.po;
import com.cf.cs.database.pojo.entity.Role;
import lombok.Builder;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
/**
* The type Auth account user.
*
* @author xajhuang @163.com
*/
@Builder
@Data
public class AuthAccountUser implements UserDetails {
private final String userName;
private final String password;
private final Long id;
private final String uid;
private final Role role;
private final boolean accountNonExpired;
private final boolean accountNonLocked;
private final boolean credentialsNonExpired;
private final boolean enabled;
private Long authTimeStamp;
private Collection<? extends GrantedAuthority> authorities;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return userName;
}
@Override
public boolean isAccountNonExpired() {
return accountNonExpired;
}
@Override
public boolean isAccountNonLocked() {
return accountNonLocked;
}
@Override
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
@Override
public boolean isEnabled() {
return enabled;
}
}

View File

@ -0,0 +1,21 @@
package com.cf.cs.authentication.pojo.po;
import lombok.Data;
import org.springframework.http.HttpMethod;
import java.io.Serial;
import java.io.Serializable;
/**
* The type Url filter item.
*
* @author xajhuang @163.com
*/
@Data
public class UrlFilterItem implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private HttpMethod method;
private String url;
}

View File

@ -0,0 +1,56 @@
package com.cf.cs.authentication.security.impl;
import com.cf.cs.authentication.misc.CasbinAuthorizeUtils;
import com.cf.cs.base.common.ErrorCode;
import com.cf.cs.base.misc.ApiContextUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.stereotype.Component;
import java.util.Optional;
import java.util.function.Supplier;
/**
* The type Custom authorization manager.
*
* @author xajhuang @163.com
*/
@Component
public class CustomAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
@Resource
private CasbinAuthorizeUtils casbinAuthorizeUtils;
@Resource
private ServerProperties serverProperties;
@Override
public AuthorizationDecision check(Supplier<Authentication> authentications, RequestAuthorizationContext context) {
// 从Supplier中获取Authentication对象
Authentication auth = authentications.get();
if (auth == null || !auth.isAuthenticated()) {
throw new AccessDeniedException(ErrorCode.ERR_LOGOUT.getDescription());
}
// 获取用户名
String username = ApiContextUtils.get().getUsername();
// 从RequestAuthorizationContext获取HttpServletRequest
HttpServletRequest request = context.getRequest();
// 获取HTTP方法
String httpMethod = request.getMethod();
String prefixUrl = Optional.ofNullable(serverProperties.getServlet().getContextPath()).orElse("");
String url = request.getRequestURI().replaceFirst("^" + prefixUrl, "");
return new AuthorizationDecision(casbinAuthorizeUtils.casbinVerifyAuthorize(username, url, httpMethod));
}
}

View File

@ -0,0 +1,34 @@
package com.cf.cs.authentication.security.impl;
import com.cf.cs.authentication.misc.SecurityResponseUtils;
import com.cf.cs.base.common.ErrorCode;
import com.cf.cs.database.service.OperationLogDataBaseService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* The type Jwt access denied handler.
*
* @author xajhuang @163.com
*/
@Component
public class JwtAccessDeniedHandler implements AccessDeniedHandler {
@Resource
private OperationLogDataBaseService optLogDbService;
@Override
public void handle(HttpServletRequest request,
HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
SecurityResponseUtils.authenticationResponse(request, response, ErrorCode.ERR_PERMISSION, accessDeniedException.getMessage(),
optLogDbService);
}
}

View File

@ -0,0 +1,32 @@
package com.cf.cs.authentication.security.impl;
import com.cf.cs.authentication.misc.SecurityResponseUtils;
import com.cf.cs.base.common.ErrorCode;
import com.cf.cs.database.service.OperationLogDataBaseService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* The type Jwt authentication entry point.
*
* @author xajhuang @163.com
*/
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Resource
private OperationLogDataBaseService optLogDbService;
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
SecurityResponseUtils.authenticationResponse(request, response, ErrorCode.ERR_PARAMEXCEPTION, authException.getMessage(), optLogDbService);
}
}

View File

@ -0,0 +1,100 @@
package com.cf.cs.authentication.security.impl;
import com.cf.cs.authentication.exception.CommonAuthException;
import com.cf.cs.authentication.interceptor.RequestBodyCacheWrapper;
import com.cf.cs.authentication.misc.JwtUtils;
import com.cf.cs.authentication.misc.SecurityResponseUtils;
import com.cf.cs.authentication.service.AccountJwtCacheService;
import com.cf.cs.base.common.ConstValue;
import com.cf.cs.base.common.ErrorCode;
import com.cf.cs.base.misc.ApiContextUtils;
import com.cf.cs.base.pojo.po.JwtCache;
import com.cf.cs.database.pojo.entity.User;
import com.cf.cs.database.service.OperationLogDataBaseService;
import io.micrometer.common.util.StringUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
/**
* The type Jwt authentication filter.
*
* @author xajhuang @163.com
*/
@Component
@Slf4j
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Resource
private JwtUtils jwtUtils;
@Resource
private UserDetailServiceImpl userDetailsService;
@Resource
private AccountJwtCacheService accountJwtCacheService;
@Resource
private OperationLogDataBaseService optLogDbService;
@Override
protected void doFilterInternal(HttpServletRequest request,
@NotNull HttpServletResponse response,
@NotNull FilterChain filterChain) throws ServletException, IOException {
String jwt = request.getHeader(jwtUtils.getHeadValue());
HttpServletRequest requestWrapper = new RequestBodyCacheWrapper(request);
// 这里如果没有jwt继续往后走因为后面还有鉴权管理器等去判断是否拥有身份凭证所以是可以放行的
// 没有jwt相当于匿名访问若有一些接口是需要权限的则不能访问这些接口
if (StringUtils.isBlank(jwt) || StringUtils.isEmpty(jwt)) {
filterChain.doFilter(requestWrapper, response);
return;
}
try {
User user = jwtUtils.parseToken(jwt);
JwtCache jwtCache = accountJwtCacheService.getAccountJwtCache(user.getUid());
if (jwtCache == null) {
handleException(requestWrapper, response, ErrorCode.ERR_TOKENNOTFOUND);
return;
}
// 缓存 JWT 以及用户信息
ApiContextUtils.setJwtUserInfo(jwtCache.jwt, user.getUsername(), user.getUid(), user.getId());
// 刷新缓存
if (System.currentTimeMillis() - jwtCache.getAddTimestamp() >= ConstValue.SECOND_OF_MINUTE * ConstValue.MS_OF_SECONDS) {
accountJwtCacheService.deleteAccountJwtCache(jwtCache.uId);
accountJwtCacheService.createAccountJwtCache(jwtCache.uId, jwtCache.jwt);
}
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUsername(), null,
userDetailsService.getUserAuthority(
user.getUid()));
SecurityContextHolder.getContext().setAuthentication(token);
// 放行
filterChain.doFilter(requestWrapper, response);
} catch (CommonAuthException e) {
handleException(requestWrapper, response, e.getErr());
} finally {
ApiContextUtils.clear();
}
}
private void handleException(HttpServletRequest request, HttpServletResponse response, ErrorCode err) throws IOException {
// 特定处理逻辑例如设置响应状态记录日志重定向等
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
SecurityResponseUtils.authenticationResponse(request, response, err, err.getDescription(), optLogDbService);
}
}

View File

@ -0,0 +1,191 @@
package com.cf.cs.authentication.security.impl;
import com.cf.cs.authentication.exception.CommonAuthException;
import com.cf.cs.authentication.misc.JwtUtils;
import com.cf.cs.authentication.misc.SecurityResponseUtils;
import com.cf.cs.authentication.pojo.po.AuthAccountUser;
import com.cf.cs.authentication.service.AccountJwtCacheService;
import com.cf.cs.authentication.service.AuthUsersService;
import com.cf.cs.base.common.ErrorCode;
import com.cf.cs.base.misc.ApiContextUtils;
import com.cf.cs.base.misc.HelperUtils;
import com.cf.cs.base.pojo.po.JwtCache;
import com.cf.cs.database.service.OperationLogDataBaseService;
import com.cf.cs.protocol.config.ProtocolConfigure;
import com.cf.cs.protocol.pojo.dto.LoginReq;
import com.cf.cs.protocol.pojo.dto.ProtocolReq;
import com.cf.cs.protocol.pojo.po.BaseRespStatus;
import com.cf.cs.protocol.pojo.vo.LoginResp;
import com.cf.cs.protocol.validation.group.ValidGroups;
import com.fasterxml.jackson.core.type.TypeReference;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.bind.annotation.RequestMethod;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
/**
* The type Jwt custom username password.
*
* @author xajhuang @163.com
*/
public class JwtCustomUsernamePassword extends UsernamePasswordAuthenticationFilter {
@Resource
private AuthUsersService usersService;
@Resource
private JwtUtils jwtUtils;
@Resource
private AccountJwtCacheService accountJwtCacheService;
@Resource
private OperationLogDataBaseService optLogDbService;
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
//获取请求头据此判断请求参数类型
String contentType = request.getContentType();
if (MediaType.APPLICATION_JSON_VALUE.startsWith(contentType)) {
//说明请求参数是 JSON
if (!RequestMethod.POST.toString().equals(request.getMethod())) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
try {
ProtocolReq<LoginReq> loginReq = HelperUtils.jsonGetObject(request.getInputStream(),
new TypeReference<>() {
});
List<String> validate = HelperUtils.validate(loginReq, ValidGroups.ProtocolCommonValid.class,
ValidGroups.LogoutReqValid.class);
// 如果校验通过validate为空否则validate包含未校验通过项
if (validate.isEmpty()) {
// 校验通过才会执行业务逻辑处理
LoginReq us = loginReq.getMsgContent();
//构建登录令牌
UsernamePasswordAuthenticationToken authRequest =
UsernamePasswordAuthenticationToken.unauthenticated(
us.getUsername(),
us.getPassword());
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
//执行真正的登录操作
return this.getAuthenticationManager().authenticate(authRequest);
} else {
throw new CommonAuthException(ErrorCode.ERR_PARAMEXCEPTION, validate.toArray(new String[0]));
}
} catch (Exception exception) {
if (exception instanceof IOException) {
throw new CommonAuthException(ErrorCode.ERR_JSON_DECODE);
} else if (exception instanceof CommonAuthException e) {
throw new CommonAuthException(e.getErr(), e.getDescription());
} else {
throw new AuthenticationServiceException(exception.getMessage(), exception.getCause());
}
}
} else {
return super.attemptAuthentication(request, response);
}
}
@Override
public void unsuccessfulAuthentication(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException failed) throws IOException {
ErrorCode err = ErrorCode.ERR_SYSTEMEXCEPTION;
BaseRespStatus rsp = new BaseRespStatus();
SecurityContextHolder.clearContext();
if (failed instanceof LockedException) {
err = ErrorCode.ERR_USERLOCK;
} else if (failed instanceof CredentialsExpiredException) {
err = ErrorCode.ERR_PASSWORD_EXPIRED;
} else if (failed instanceof AccountExpiredException) {
err = ErrorCode.ERR_ACCOUNT;
} else if (failed instanceof DisabledException) {
err = ErrorCode.ERR_ACCOUNT;
} else if (failed instanceof BadCredentialsException) {
err = ErrorCode.ERR_PASSWORD;
}
if (failed instanceof AuthenticationServiceException) {
if (failed.getCause() instanceof CommonAuthException ex) {
rsp.setStatus(ex.getErr().getCode());
} else {
rsp.setStatus(ErrorCode.ERR_ACCOUNT.getCode());
}
rsp.setMessage(new String[] {failed.getMessage()});
} else if (failed instanceof CommonAuthException ex) {
rsp.setStatus(ex.getErr().getCode());
rsp.setMessage(ex.getDescription());
} else {
rsp.setStatus(err.getCode());
rsp.setMessage(new String[] {err.getDescription()});
}
SecurityResponseUtils.authenticationResponse(request, response, rsp, Arrays.toString(rsp.getMessage()),
optLogDbService);
}
@Override
public void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain,
Authentication authResult) throws IOException {
AuthAccountUser au = usersService.getAuthAccountByUserName(authResult.getName());
JwtCache jc = accountJwtCacheService.getAccountJwtCache(au.getUid());
if (jc != null) {
accountJwtCacheService.deleteAccountJwtCache(au.getUid());
}
String jwt = jwtUtils.getToken(au.getUid());
jc = accountJwtCacheService.createAccountJwtCache(au.getUid(), jwt);
LoginResp loginRsp = LoginResp.builder()
.username(authResult.getName())
.token(jc.getJwt())
.logTime(System.currentTimeMillis())
.expireTime(System.currentTimeMillis() + ProtocolConfigure.TIMEOUT_OF_SECONDS * 1000L)
.build();
loginRsp.setMessage(new String[] {ErrorCode.ERR_OK.getDescription()});
loginRsp.setStatus(ErrorCode.ERR_OK.getCode());
SecurityContextHolder.getContext().setAuthentication(authResult);
// Fire event
if (this.eventPublisher != null) {
eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
}
// 缓存 JWT 以及用户信息
ApiContextUtils.setJwtUserInfo(jwt, au.getUsername(), au.getUid(), au.getId());
try {
SecurityResponseUtils.authenticationResponse(request, response, loginRsp,
"[" + authResult.getName() + "] login", optLogDbService);
} finally {
ApiContextUtils.clear();
}
}
}

View File

@ -0,0 +1,61 @@
package com.cf.cs.authentication.security.impl;
import com.cf.cs.authentication.misc.SecurityResponseUtils;
import com.cf.cs.authentication.service.AccountJwtCacheService;
import com.cf.cs.base.common.ErrorCode;
import com.cf.cs.base.misc.ApiContextUtils;
import com.cf.cs.base.misc.HelperUtils;
import com.cf.cs.base.pojo.po.ApiContext;
import com.cf.cs.database.service.OperationLogDataBaseService;
import com.cf.cs.protocol.pojo.vo.LogoutResp;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Arrays;
/**
* The type Jwt logout handler.
*
* @author xajhuang @163.com
*/
@Component
public class JwtLogoutHandler implements LogoutHandler {
@Resource
private OperationLogDataBaseService optLogDbService;
@Resource
private AccountJwtCacheService accountJwtCacheService;
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
LogoutResp rsp = new LogoutResp();
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
try {
ApiContext ctx = ApiContextUtils.get();
String username = ctx.getUsername();
if (!HelperUtils.stringNotEmptyOrNull(username)) {
rsp.setStatus(ErrorCode.ERR_TOKENNOTFOUND.getCode());
rsp.setMessage(new String[] {ErrorCode.ERR_TOKENNOTFOUND.getDescription()});
} else {
// 校验通过才会执行业务逻辑处理
accountJwtCacheService.deleteAccountJwtCache(ctx.getUid());
rsp.setStatus(ErrorCode.ERR_OK.getCode());
rsp.setMessage(new String[] {ErrorCode.ERR_OK.getDescription()});
}
rsp.setUsername(username);
SecurityResponseUtils.authenticationResponse(request, response, rsp, Arrays.toString(rsp.getMessage()),
optLogDbService);
} catch (IOException e) {
throw new AuthenticationServiceException(e.getMessage());
}
}
}

View File

@ -0,0 +1,37 @@
package com.cf.cs.authentication.security.impl;
import com.cf.cs.authentication.misc.SecurityResponseUtils;
import com.cf.cs.base.common.ErrorCode;
import com.cf.cs.database.service.OperationLogDataBaseService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* The type Jwt logout success handler.
*
* @author xajhuang @163.com
*/
@Component
public class JwtLogoutSuccessHandler implements LogoutSuccessHandler {
@Resource
private OperationLogDataBaseService optLogDbService;
@Override
public void onLogoutSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException {
if (authentication != null) {
new SecurityContextLogoutHandler().logout(request, response, authentication);
}
SecurityResponseUtils.authenticationResponse(request, response, ErrorCode.ERR_OK, "logout", optLogDbService);
}
}

View File

@ -0,0 +1,55 @@
package com.cf.cs.authentication.security.impl;
import com.cf.cs.authentication.exception.CommonAuthException;
import com.cf.cs.authentication.pojo.po.AuthAccountUser;
import com.cf.cs.authentication.service.AuthUsersService;
import com.cf.cs.base.common.ErrorCode;
import jakarta.annotation.Resource;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* The type User detail service.
*
* @author xajhuang @163.com
*/
@Service
public class UserDetailServiceImpl implements UserDetailsService {
@Resource
private AuthUsersService authUsersService;
@Override
public UserDetails loadUserByUsername(String username) {
AuthAccountUser au = authUsersService.getAuthAccountByUserName(username);
if (au == null) {
throw new CommonAuthException(ErrorCode.ERR_USERNOTFOUND);
}
if (!au.isAccountNonLocked()) {
throw new CommonAuthException(ErrorCode.ERR_USERLOCK);
}
if (!au.isEnabled()) {
throw new CommonAuthException(ErrorCode.ERR_ACCOUNT);
}
au.setAuthorities(getUserAuthority(au.getUid()));
return au;
}
/**
* Gets user authority.
*
* @param userId the user id
* @return the user authority
*/
public List<GrantedAuthority> getUserAuthority(String userId) {
return AuthorityUtils.commaSeparatedStringToAuthorityList(userId);
}
}

View File

@ -0,0 +1,35 @@
package com.cf.cs.authentication.service;
import com.cf.cs.base.pojo.po.JwtCache;
/**
* The interface Account jwt cache service.
*
* @author xajhuang @163.com
*/
public interface AccountJwtCacheService {
/**
* Gets account jwt cache.
*
* @param userId the user id
* @return the account jwt cache
*/
JwtCache getAccountJwtCache(String userId);
/**
* Create account jwt cache.
*
* @param userId the user id
* @param jwt the jwt
* @return the jwt cache
*/
JwtCache createAccountJwtCache(String userId, String jwt);
/**
* Delete account jwt cache.
*
* @param userId the user id
*/
void deleteAccountJwtCache(String userId);
}

View File

@ -0,0 +1,26 @@
package com.cf.cs.authentication.service;
import com.cf.cs.authentication.pojo.po.AuthAccountUser;
/**
* The interface Auth users service.
*
* @author xajhuang @163.com
*/
public interface AuthUsersService {
/**
* Gets auth account by username.
*
* @param username the username
* @return the auth account by username
*/
AuthAccountUser getAuthAccountByUserName(String username);
/**
* Remove user by user name.
*
* @param username the username
*/
void removeUserByUserName(String username);
}

View File

@ -0,0 +1,35 @@
package com.cf.cs.authentication.service.impl;
import com.cf.cs.authentication.service.AccountJwtCacheService;
import com.cf.cs.base.pojo.po.JwtCache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
/**
* The type Account jwt cache service.
*
* @author xajhuang @163.com
*/
@Service
@Slf4j
public class AccountJwtCacheServiceImpl implements AccountJwtCacheService {
@Override
@Cacheable(value = "JWT_CACHE", key = "'user'+#userId", sync = true)
public JwtCache getAccountJwtCache(String userId) {
return null;
}
@Override
@CachePut(value = "JWT_CACHE", key = "'user'+#userId")
public JwtCache createAccountJwtCache(String userId, String jwt) {
return JwtCache.builder().addTimestamp(System.currentTimeMillis()).jwt(jwt).uId(userId).build();
}
@Override
@CacheEvict(value = "JWT_CACHE", key = "'user'+#userId")
public void deleteAccountJwtCache(String userId) {
}
}

View File

@ -0,0 +1,67 @@
package com.cf.cs.authentication.service.impl;
import com.cf.cs.authentication.pojo.po.AuthAccountUser;
import com.cf.cs.authentication.service.AuthUsersService;
import com.cf.cs.base.common.CommonStatus;
import com.cf.cs.database.mapper.RoleMapper;
import com.cf.cs.database.pojo.entity.Role;
import com.cf.cs.database.pojo.entity.User;
import com.cf.cs.database.pojo.entity.UserCredential;
import com.cf.cs.database.service.UserDataBaseService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
/**
* The type Auth users cache service.
*
* @author xajhuang @163.com
*/
@Service
@Slf4j
public class AuthUsersCacheServiceImpl implements AuthUsersService {
@Resource
private UserDataBaseService userService;
@Resource
private RoleMapper roleMapper;
@Override
@Cacheable(value = "AUTH_CACHE", key = "'user'+#username", sync = true)
public AuthAccountUser getAuthAccountByUserName(String username) {
User user = userService.getAccountUserByName(username);
if (user == null) {
return null;
}
Role role = roleMapper.selectOneById(user.getRoleId());
if (role == null) {
return null;
}
UserCredential uc = user.getUserCredential();
return AuthAccountUser.builder()
.userName(user.getUsername())
.password(uc.getCredential())
.authTimeStamp(System.currentTimeMillis())
.id(user.getId())
.uid(user.getUid())
.role(role)
//.authorities(getUserAuthority(uc.getUserId()))
.accountNonExpired(true)
.accountNonLocked(!uc.getState().equals(CommonStatus.LOCKED.getValue()))
.credentialsNonExpired(true)
.enabled(uc.getState().equals(CommonStatus.NORMAL.getValue()))
.build();
}
@Override
@CacheEvict(value = "AUTH_CACHE", key = "'user'+#username")
public void removeUserByUserName(String username) {
}
}

View File

@ -0,0 +1,15 @@
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act, eft
# RBAC角色继承关系的定义
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))
[matchers]
m = g(r.sub, p.sub) && keyMatch2(r.obj, p.obj) && regexMatch(r.act, p.act)

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,21 @@
package com.cf.cs.authentication;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
/**
* The type Cs authentication application tests.
*
* @author xajhuang @163.com
*/
@SpringBootTest
class CsAuthenticationApplicationTests {
/**
* Context loads.
*/
@Test
void contextLoads() {
}
}

View File

@ -1,5 +1,6 @@
package com.cf.cs.base;
import com.houkunlin.system.dict.starter.SystemDictScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@ -8,6 +9,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
*
* @author xajhuang @163.com
*/
@SystemDictScan
@SpringBootApplication
public class CsBaseApplication {

View File

@ -11,7 +11,7 @@ import lombok.Getter;
@Getter
public enum CachePool {
/**
* Auth cache cache pool.
* Auth cache pool.
*/
AUTH_CACHE("AUTH_CACHE", 1800, 1000, 100),
/**

View File

@ -10,6 +10,10 @@ public class ConstValue {
* The constant STRING_HTTP_AUTH_HEAD.
*/
public static final String STRING_HTTP_AUTH_HEAD = "Bearer ";
public static final long MS_OF_SECONDS = 1000L;
public static final long SECOND_OF_MINUTE = 60;
public static final int MAX_IPV4_LEN = 15;
/**
* The constant IP_ADDR_REG.

View File

@ -0,0 +1,33 @@
package com.cf.cs.base.config;
import jakarta.annotation.PostConstruct;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.util.Optional;
/**
* The type Jwt configure.
*
* @author xajhuang @163.com
*/
@Configuration
@ConfigurationProperties(prefix = "jwt")
@Slf4j
@Data
public class JwtConfigure {
private String secretKey;
private Long expireTime;
private String httpHead;
@PostConstruct
private void initGlobalValue() {
log.info("Current: secretKey = {}, httpHead = {}, expireTime = {}", secretKey, httpHead, expireTime);
secretKey = Optional.ofNullable(secretKey).orElse("");
httpHead = Optional.ofNullable(httpHead).orElse("Authorization");
expireTime = Optional.ofNullable(expireTime).orElse((long) (7 * 24 * 3600));
}
}

View File

@ -15,7 +15,7 @@ public class CommonErrorCodeException extends RuntimeException{
/**
* Instantiates a new Common error code exception.
*
* @param err the err
* @param err to err
*/
public CommonErrorCodeException(ErrorCode err) {
super(err.getDescription());
@ -26,7 +26,7 @@ public class CommonErrorCodeException extends RuntimeException{
/**
* Instantiates a new Common error code exception.
*
* @param err the err
* @param err to err
* @param readme the readme
*/
public CommonErrorCodeException(ErrorCode err, String readme) {
@ -38,7 +38,7 @@ public class CommonErrorCodeException extends RuntimeException{
/**
* Instantiates a new Common error code exception.
*
* @param err the err
* @param err to err
* @param readme the readme
*/
public CommonErrorCodeException(ErrorCode err, String[] readme) {

View File

@ -1,6 +1,7 @@
package com.cf.cs.base.misc;
import com.cf.cs.base.common.ConstValue;
import com.cf.cs.base.config.ObjectMapperProvider;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
@ -60,7 +61,7 @@ public class HelperUtils {
}
/**
* Bytes to hex string string.
* Bytes to hex string.
*
* @param bArray the b array
* @return the string
@ -93,7 +94,7 @@ public class HelperUtils {
}
/**
* Input stream 2 string string.
* Input stream 2 string.
*
* @param inputStream the input stream
* @return the string
@ -323,7 +324,7 @@ public class HelperUtils {
}
}
// 对于通过多个代理的情况分割出第一个 IP
if (ip != null && ip.length() > 15) {
if (ip != null && ip.length() > ConstValue.MAX_IPV4_LEN) {
if (ip.indexOf(separator) > 0) {
ip = ip.substring(0, ip.indexOf(separator));
}

View File

@ -0,0 +1,26 @@
package com.cf.cs.base.pojo.po;
import lombok.Builder;
import lombok.Data;
/**
* The type Jwt cache.
*
* @author xajhuang @163.com
*/
@Data
@Builder
public class JwtCache {
/**
* The U id.
*/
public String uId;
/**
* The Add timestamp.
*/
public long addTimestamp;
/**
* The Jwt.
*/
public String jwt;
}

View File

@ -3,9 +3,17 @@ package com.cf.cs.base;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
/**
* The type Cs base application tests.
*
* @author xajhuang @163.com
*/
@SpringBootTest
class CsBaseApplicationTests {
/**
* Context loads.
*/
@Test
void contextLoads() {
}

View File

@ -11,12 +11,12 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CsCryptoApplication {
/**
* The entry point of application.
*
* @param args the input arguments
*/
public static void main(String[] args) {
/**
* The entry point of application.
*
* @param args the input arguments
*/
public static void main(String[] args) {
SpringApplication.run(CsCryptoApplication.class, args);
}

View File

@ -5,6 +5,11 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* The interface Encryption protocol.
*
* @author xajhuang @163.com
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptionProtocol {

View File

@ -194,7 +194,7 @@ public class CryptoHelper {
}
/**
* Des encryption byte [ ].
* Deencryption byte [ ].
*
* @param plaintext the plaintext
* @param desKey the des key

View File

@ -13,6 +13,11 @@ import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* The type Mybatis flex configure.
*
* @author xajhuang @163.com
*/
@Configuration
@MapperScan(value = {"com.cf.cs.database.mapper"})
public class MybatisFlexConfigure {
@ -33,6 +38,11 @@ public class MybatisFlexConfigure {
}
}
/**
* Logic delete processor logic delete processor.
*
* @return the logic delete processor
*/
@Bean
public LogicDeleteProcessor logicDeleteProcessor(){
return new DateTimeLogicDeleteProcessor();

View File

@ -4,7 +4,15 @@ import com.mybatisflex.core.keygen.IKeyGenerator;
import java.util.UUID;
/**
* The type Uuid key generator.
*
* @author xajhuang @163.com
*/
public class UuidKeyGenerator implements IKeyGenerator {
/**
* The constant COMMON_UUID.
*/
public static final String COMMON_UUID = "UUID";
@Override

View File

@ -7,7 +7,7 @@ import org.apache.ibatis.annotations.Mapper;
/**
* 字典数据表 映射层
*
* @author mybatis-flex-helper automatic generation
* @author mybatis -flex-helper automatic generation
* @since 1.0
*/
@Mapper

View File

@ -7,7 +7,7 @@ import org.apache.ibatis.annotations.Mapper;
/**
* 字典类型表 映射层
*
* @author mybatis-flex-helper automatic generation
* @author mybatis -flex-helper automatic generation
* @since 1.0
*/
@Mapper

View File

@ -7,7 +7,7 @@ import org.apache.ibatis.annotations.Mapper;
/**
* 系统操作日志 映射层
*
* @author mybatis-flex-helper automatic generation
* @author mybatis -flex-helper automatic generation
* @since 1.0
*/
@Mapper

View File

@ -7,7 +7,7 @@ import org.apache.ibatis.annotations.Mapper;
/**
* 映射层
*
* @author mybatis-flex-helper automatic generation
* @author mybatis -flex-helper automatic generation
* @since 1.0
*/
@Mapper

View File

@ -7,7 +7,7 @@ import org.apache.ibatis.annotations.Mapper;
/**
* 映射层
*
* @author mybatis-flex-helper automatic generation
* @author mybatis -flex-helper automatic generation
* @since 1.0
*/
@Mapper

View File

@ -7,7 +7,7 @@ import org.apache.ibatis.annotations.Mapper;
/**
* 权限 映射层
*
* @author mybatis-flex-helper automatic generation
* @author mybatis -flex-helper automatic generation
* @since 1.0
*/
@Mapper

View File

@ -7,7 +7,7 @@ import org.apache.ibatis.annotations.Mapper;
/**
* 权限资源 映射层
*
* @author mybatis-flex-helper automatic generation
* @author mybatis -flex-helper automatic generation
* @since 1.0
*/
@Mapper

View File

@ -7,7 +7,7 @@ import org.apache.ibatis.annotations.Mapper;
/**
* 用户认证 映射层
*
* @author mybatis-flex-helper automatic generation
* @author mybatis -flex-helper automatic generation
* @since 1.0
*/
@Mapper

View File

@ -9,8 +9,8 @@ import java.util.List;
/**
* 用户表(User)表数据库访问层
*
* @author makejava
* @since 2023-12-19 17:35:25
* @author makejava @163.com
* @since 2023 -12-19 17:35:25
*/
public interface UserMapper extends BaseMapper<User> {
@ -18,7 +18,7 @@ public interface UserMapper extends BaseMapper<User> {
* 批量新增或按主键更新数据MyBatis原生foreach方法
*
* @param entities List<User> 实例对象列表
* @return 影响行数
* @return 影响行数 int
* @throws org.springframework.jdbc.BadSqlGrammarException 入参是空List的时候会抛SQL语句错误的异常请自行校验入参
*/
int insertOrUpdateBatch(@Param("entities") List<User> entities);

View File

@ -8,6 +8,12 @@ import lombok.NoArgsConstructor;
import java.util.List;
/**
* The type Page results.
*
* @param <T> the type parameter
* @author xajhuang @163.com
*/
@Data
@Builder
@NoArgsConstructor

View File

@ -7,6 +7,11 @@ import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* The type Res perm info.
*
* @author xajhuang @163.com
*/
@Schema(name = "资源权限信息")
@Data
@Builder

View File

@ -64,7 +64,7 @@ public interface OperationLogDataBaseService extends IService<OperationLog> {
* @param pageNumber the page number
* @param pageSize the page size
* @param totalSize the total size
* @param userName the user name
* @param userName the username
* @return the system operation summary
*/
Page<OperationLogSummary> getSystemOperationSummary(Long pageNumber, Long pageSize, Long totalSize, List<String> userName);

View File

@ -0,0 +1,31 @@
package com.cf.cs.database.service;
import com.cf.cs.database.pojo.entity.RoleResource;
import com.mybatisflex.core.service.IService;
import java.util.List;
/**
* 权限资源 服务层
*
* @author mybatis -flex-helper automatic generation
* @since 1.0
*/
public interface RoleResourceService extends IService<RoleResource> {
/**
* Gets role resource by role name.
*
* @param roleName the role name
* @return the role resource by role name
*/
List<RoleResource> getRoleResourceByRoleName(String roleName);
/**
* Gets role resource by role id.
*
* @param roleId the role id
* @return the role resource by role id
*/
List<RoleResource> getRoleResourceByRoleId(Long roleId);
}

View File

@ -12,28 +12,88 @@ import java.util.List;
/**
* 用户表(User)表服务接口
*
* @author makejava
* @since 2023-12-19 17:35:25
* @author makejava @163.com
* @since 2023 -12-19 17:35:25
*/
public interface UserDataBaseService extends IService<User> {
/**
* Gets account user by name.
*
* @param username the username
* @return the account user by name
*/
User getAccountUserByName(String username);
/**
* Gets account user by uid.
*
* @param uid the uid
* @return the account user by uid
*/
User getAccountUserByUid(String uid);
/**
* Gets account user by id.
*
* @param userId the user id
* @return the account user by id
*/
User getAccountUserById(Long userId);
/**
* Gets user info by id.
*
* @param userId the user id
* @return the user info by id
*/
UserInfo getUserInfoById(Long userId);
/**
* Gets user info by uid.
*
* @param uid the uid
* @return the user info by uid
*/
UserInfo getUserInfoByUid(String uid);
/**
* Gets user info by username.
*
* @param username the username
* @return the user info by username
*/
UserInfo getUserInfoByUsername(String username);
/**
* Gets current user info.
*
* @return the current user info
*/
UserInfo getCurrentUserInfo();
/**
* Gets all user info.
*
* @param pageNumber the page number
* @param pageSize the page size
* @param totalSize the total size
* @return the all user info
*/
PageResults<UserInfo> getAllUserInfo(Long pageNumber, Long pageSize, Long totalSize);
/**
* Gets current user resource perm.
*
* @return the current user resource perm
*/
List<ResPermInfo> getCurrentUserResourcePerm();
/**
* Gets user resource perm.
*
* @param userId the user id
* @return the user resource perm
*/
List<ResPermInfo> getUserResourcePerm(Long userId);
}

View File

@ -7,8 +7,8 @@ import com.cf.cs.base.exception.CommonErrorCodeException;
import com.cf.cs.base.misc.ApiContextUtils;
import com.cf.cs.base.misc.HelperUtils;
import com.cf.cs.base.pojo.po.ApiContext;
import com.cf.cs.database.pojo.entity.OperationLog;
import com.cf.cs.database.mapper.OperationLogMapper;
import com.cf.cs.database.pojo.entity.OperationLog;
import com.cf.cs.database.pojo.po.OperationLogDetails;
import com.cf.cs.database.pojo.po.OperationLogSummary;
import com.cf.cs.database.service.OperationLogDataBaseService;
@ -35,13 +35,14 @@ import static com.mybatisflex.core.query.QueryMethods.select;
/**
* 系统操作日志 服务层实现
*
* @author mybatis-flex-helper automatic generation
* @author mybatis -flex-helper automatic generation
* @since 1.0
*/
@Service
@Slf4j
public class OperationLogDataBaseServiceImpl extends ServiceImpl<OperationLogMapper, OperationLog> implements OperationLogDataBaseService {
private final int MAX_DB_STRING = 4090;
private final int MAX_DB_STRING = 4090;
private final String ERROR_URL = "/error";
@Resource
private ServerProperties serverProperties;
@ -72,7 +73,7 @@ public class OperationLogDataBaseServiceImpl extends ServiceImpl<OperationLogMap
ApiContext ctx = ApiContextUtils.get();
OperationLog optLog = new OperationLog();
if (request.getRequestURI().startsWith(CommonConfigure.PROJECT_PREFIX_URL + "/error")) {
if (request.getRequestURI().startsWith(CommonConfigure.PROJECT_PREFIX_URL + ERROR_URL)) {
return;
}
@ -94,14 +95,17 @@ public class OperationLogDataBaseServiceImpl extends ServiceImpl<OperationLogMap
optLog.setHttpPath(url);
// 仅处理 RESTful 接口
if (url.startsWith("/api")) {
String API_PREFIX = "/api";
if (url.startsWith(API_PREFIX)) {
// 登录接口不包含 Authorization 信息
if (url.lastIndexOf("login") != -1) {
optLog.setCallFunction("login");
String LOGIN_URL = "login";
if (url.lastIndexOf(LOGIN_URL) != -1) {
optLog.setCallFunction(LOGIN_URL);
optLog.setUserId(ctx.getId() != null ? ctx.getId() : -1L);
} else {
if (url.lastIndexOf("logout") != -1) {
optLog.setCallFunction("logout");
String LOGOUT_URL = "logout";
if (url.lastIndexOf(LOGOUT_URL) != -1) {
optLog.setCallFunction(LOGOUT_URL);
}
if (HelperUtils.stringNotEmptyOrNull(ctx.getJwt())) {
@ -203,7 +207,7 @@ public class OperationLogDataBaseServiceImpl extends ServiceImpl<OperationLogMap
ApiContext ctx = ApiContextUtils.get();
OperationLog optLog = new OperationLog();
if (request.getRequestURI().startsWith(CommonConfigure.PROJECT_PREFIX_URL + "/error")) {
if (request.getRequestURI().startsWith(CommonConfigure.PROJECT_PREFIX_URL + ERROR_URL)) {
return;
}

View File

@ -0,0 +1,59 @@
package com.cf.cs.database.service.impl;
import com.cf.cs.database.mapper.RoleMapper;
import com.cf.cs.database.mapper.RoleResourceMapper;
import com.cf.cs.database.pojo.entity.Role;
import com.cf.cs.database.pojo.entity.RoleResource;
import com.cf.cs.database.service.RoleResourceService;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import static com.cf.cs.database.pojo.entity.table.RoleResourceTableDef.ROLE_RESOURCE;
import static com.cf.cs.database.pojo.entity.table.RoleTableDef.ROLE;
/**
* 权限资源 服务层实现
*
* @author mybatis -flex-helper automatic generation
* @since 1.0
*/
@Service
public class RoleResourceServiceImpl extends ServiceImpl<RoleResourceMapper, RoleResource> implements RoleResourceService {
@Resource
private RoleMapper roleMapper;
@Resource
private RoleResourceMapper roleResourceMapper;
@Override
public List<RoleResource> getRoleResourceByRoleName(String roleName) {
QueryWrapper wrapper = QueryWrapper.create().from(ROLE).select().where(ROLE.NAME.eq(roleName));
Role role = roleMapper.selectOneByQuery(wrapper);
if (role == null) {
return new ArrayList<>();
} else {
wrapper = QueryWrapper.create().from(ROLE_RESOURCE).select();
return roleResourceMapper.selectListWithRelationsByQuery(wrapper);
}
}
@Override
public List<RoleResource> getRoleResourceByRoleId(Long roleId) {
QueryWrapper wrapper = QueryWrapper.create().from(ROLE).select().where(ROLE.ID.eq(roleId));
Role role = roleMapper.selectOneByQuery(wrapper);
if (role == null) {
return new ArrayList<>();
} else {
wrapper = QueryWrapper.create().from(ROLE_RESOURCE).select().where(ROLE_RESOURCE.ROLE_ID.eq(roleId));
return roleResourceMapper.selectListWithRelationsByQuery(wrapper);
}
}
}

View File

@ -24,9 +24,7 @@ import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.HashMap;
@ -39,8 +37,8 @@ import static com.cf.cs.database.pojo.entity.table.UserTableDef.USER;
/**
* 用户表(User)表服务实现类
*
* @author makejava
* @since 2023-12-19 17:35:26
* @author makejava @163.com
* @since 2023 -12-19 17:35:26
*/
@Service("userService")
@Slf4j
@ -293,6 +291,9 @@ public class UserDataBaseServiceImpl extends ServiceImpl<UserMapper, User> imple
return true;
}
/**
* Init.
*/
@PostConstruct
public void init() {
// 在组件初始化后执行的逻辑

View File

@ -3,9 +3,17 @@ package com.cf.cs.database;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
/**
* The type Cs database application tests.
*
* @author xajhuang @163.com
*/
@SpringBootTest
class CsDatabaseApplicationTests {
/**
* Context loads.
*/
@Test
void contextLoads() {
}

View File

@ -11,12 +11,12 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CsProtocolApplication {
/**
* The entry point of application.
*
* @param args the input arguments
*/
public static void main(String[] args) {
/**
* The entry point of application.
*
* @param args the input arguments
*/
public static void main(String[] args) {
SpringApplication.run(CsProtocolApplication.class, args);
}

View File

@ -0,0 +1,44 @@
package com.cf.cs.protocol.pojo.dto;
import com.cf.cs.base.misc.HelperUtils;
import com.cf.cs.protocol.validation.group.ValidGroups;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
/**
* The type Login req.
*
* @author xajhuang @163.com
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class LoginReq {
@NotBlank(message = "username 用户名不能为空", groups = ValidGroups.LogoutReqValid.class)
@Pattern(regexp = HelperUtils.UN_EXPECT_REGEX_CHARS,
flags = Pattern.Flag.CASE_INSENSITIVE,
message = "username 用户名存在非法字符串",
groups = ValidGroups.LogoutReqValid.class)
private String username;
/**
* The Password.
*/
@NotBlank(message = "password 密码不能为空", groups = ValidGroups.LoginReqValid.class)
@Length(min = 32, max = 64,
message = "password 密码长度必须为SHA256编码后的长度",
groups = ValidGroups.LoginReqValid.class)
@Pattern(regexp = HelperUtils.UN_EXPECT_REGEX_CHARS,
flags = Pattern.Flag.CASE_INSENSITIVE,
message = "password 密码存在非法字符串",
groups = ValidGroups.LoginReqValid.class)
private String password;
}

View File

@ -0,0 +1,16 @@
package com.cf.cs.protocol.pojo.dto;
import com.cf.cs.protocol.pojo.base.BaseProtocol;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* The type Protocol req.
*
* @param <T> the type parameter
* @author xajhuang @163.com
*/
@NoArgsConstructor
@ToString
public class ProtocolReq<T> extends BaseProtocol<T> {
}

View File

@ -0,0 +1,29 @@
package com.cf.cs.protocol.pojo.vo;
import com.cf.cs.protocol.pojo.po.BaseRespStatus;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* The type Login resp.
*
* @author xajhuang @163.com
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"userName", "token", "logTime", "expireTime", "status", "message"})
public class LoginResp extends BaseRespStatus {
private String username;
private String token;
private Long logTime;
private Long expireTime;
}

View File

@ -0,0 +1,38 @@
package com.cf.cs.protocol.pojo.vo;
import com.cf.cs.protocol.pojo.po.BaseRespStatus;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* The type Logout resp.
*
* @author xajhuang @163.com
*/
@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"username", "status", "message"})
public class LogoutResp extends BaseRespStatus {
private String username;
/**
* Instantiates a new Logout resp.
*
* @param username the username
* @param status the status
* @param message the message
*/
@Builder
public LogoutResp(String username, Integer status, String[] message) {
super(status, message);
this.username = username;
}
}

View File

@ -45,7 +45,7 @@ public class ProtocolResp<T> extends BaseProtocol<T> {
* Result protocol resp.
*
* @param <T> the type parameter
* @param err the err
* @param err to err
* @param respMsg the resp msg
* @return the protocol resp
*/
@ -56,7 +56,7 @@ public class ProtocolResp<T> extends BaseProtocol<T> {
/**
* Result protocol resp.
*
* @param err the err
* @param err to err
* @return the protocol resp
*/
public static ProtocolResp<BaseRespStatus> result(ErrorCode err) {

View File

@ -1,6 +1,7 @@
package com.cf.cs.protocol.validation.valids.impl;
import com.cf.cs.base.common.ConstValue;
import com.cf.cs.protocol.config.ProtocolConfigure;
import com.cf.cs.protocol.validation.valids.ValidProtocolTimestamp;
import jakarta.validation.ConstraintValidator;
@ -40,7 +41,7 @@ public class ValidProtocolTimestampImpl implements ConstraintValidator<ValidProt
//重新添加错误提示语句
constraintValidatorContext.buildConstraintViolationWithTemplate(errMsg).addConstraintViolation();
return false;
} else if (System.currentTimeMillis() - timeStamp > ProtocolConfigure.TIMEOUT_OF_SECONDS * 1000L) {
} else if (System.currentTimeMillis() - timeStamp > ProtocolConfigure.TIMEOUT_OF_SECONDS * ConstValue.MS_OF_SECONDS) {
String errMsg = String.format("请求时间[%s] 延时超过当前服务器时间[%s] 允许范围 %d(S)", date, current,
ProtocolConfigure.TIMEOUT_OF_SECONDS);
//禁用默认的message的值

View File

@ -3,9 +3,17 @@ package com.cf.cs.protocol;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
/**
* The type Cs protocol application tests.
*
* @author xajhuang @163.com
*/
@SpringBootTest
class CsProtocolApplicationTests {
/**
* Context loads.
*/
@Test
void contextLoads() {
}

View File

@ -79,6 +79,12 @@
<version>${cs-package.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.cf.cs</groupId>
<artifactId>cs-authentication</artifactId>
<version>${cs-package.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
@ -90,6 +96,34 @@
<classifier>exec</classifier>
</configuration>
</plugin>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>4.9.10</version>
<executions>
<execution>
<id>get-the-git-infos</id>
<goals>
<goal>revision</goal>
</goals>
<phase>initialize</phase>
</execution>
</executions>
<configuration>
<failOnNoGitDirectory>false</failOnNoGitDirectory>
<verbose>false</verbose>
<offline>true</offline>
<dateFormat>yyyy-MM-dd'T'HH:mm:ssZ</dateFormat>
<generateGitPropertiesFile>true</generateGitPropertiesFile>
<generateGitPropertiesFilename>${project.basedir}/src/main/resources/git.properties
</generateGitPropertiesFilename>
<excludeProperties>
<excludeProperty>git.commit.message.*</excludeProperty>
<excludeProperty>git.commit.user.*</excludeProperty>
<excludeProperty>git.remote.origin.*</excludeProperty>
</excludeProperties>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -8,7 +8,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
*
* @author xajhuang @163.com
*/
@SpringBootApplication(scanBasePackages = {"com.cf.cs.base", "com.cf.cs.database", "com.cf.cs.protocol",
@SpringBootApplication(scanBasePackages = {"com.cf.cs.base", "com.cf.cs.database", "com.cf.cs.protocol", "com.cf.cs.authentication",
"com.cf.cs.services", "com.cf.cs.restful", "com.cf.cs.web"})
public class CsRestfulApplication {

View File

@ -1,4 +1,4 @@
package com.cf.cs.web.configure;
package com.cf.cs.restful.configure;
import jakarta.annotation.PostConstruct;
import lombok.Getter;

View File

@ -7,7 +7,7 @@ import com.cf.cs.protocol.pojo.po.VersionInfo;
import com.cf.cs.protocol.pojo.vo.ProtocolResp;
import com.cf.cs.protocol.pojo.vo.VersionResp;
import com.cf.cs.base.annotation.OperationLogAnnotation;
import com.cf.cs.web.configure.ProjectGitVersionInfo;
import com.cf.cs.restful.configure.ProjectGitVersionInfo;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@ -17,6 +17,11 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* The type Common framework api.
*
* @author xajhuang @163.com
*/
@RestController
@Slf4j
@Tag(name = "通用接口")
@ -25,6 +30,11 @@ public class CommonFrameworkApi {
@Resource
private ProjectGitVersionInfo prgVer;
/**
* Gets version.
*
* @return the version
*/
@EncryptionProtocol
@DecryptionProtocol
@PostMapping("/version")
@ -43,6 +53,11 @@ public class CommonFrameworkApi {
.build());
}
/**
* Gets version v 2.
*
* @return the version v 2
*/
@GetMapping("/version")
@ResponseBody
@EncryptionProtocol

View File

@ -3,9 +3,17 @@ package com.cf.cs.restful;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
/**
* The type Cs restful application tests.
*
* @author xajhuang @163.com
*/
@SpringBootTest
class CsRestfulApplicationTests {
/**
* Context loads.
*/
@Test
void contextLoads() {
}

View File

@ -3,9 +3,17 @@ package com.cf.cs.services;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
/**
* The type Cs services application tests.
*
* @author xajhuang @163.com
*/
@SpringBootTest
class CsServicesApplicationTests {
/**
* Context loads.
*/
@Test
void contextLoads() {
}

View File

@ -36,34 +36,6 @@
<classifier>exec</classifier>
</configuration>
</plugin>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>4.9.10</version>
<executions>
<execution>
<id>get-the-git-infos</id>
<goals>
<goal>revision</goal>
</goals>
<phase>initialize</phase>
</execution>
</executions>
<configuration>
<failOnNoGitDirectory>false</failOnNoGitDirectory>
<verbose>false</verbose>
<offline>true</offline>
<dateFormat>yyyy-MM-dd'T'HH:mm:ssZ</dateFormat>
<generateGitPropertiesFile>true</generateGitPropertiesFile>
<generateGitPropertiesFilename>${project.basedir}/src/main/resources/git.properties
</generateGitPropertiesFilename>
<excludeProperties>
<excludeProperty>git.commit.message.*</excludeProperty>
<excludeProperty>git.commit.user.*</excludeProperty>
<excludeProperty>git.remote.origin.*</excludeProperty>
</excludeProperties>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -3,9 +3,19 @@ package com.cf.cs.web;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* The type Cs web application.
*
* @author xajhuang @163.com
*/
@SpringBootApplication
public class CsWebApplication {
/**
* The entry point of application.
*
* @param args the input arguments
*/
public static void main(String[] args) {
SpringApplication.run(CsWebApplication.class, args);
}

View File

@ -9,7 +9,7 @@ import org.springframework.stereotype.Component;
/**
* The type System initial.
*
* @author xajhuang@163.com
* @author xajhuang @163.com
*/
@Component
@Slf4j

View File

@ -3,9 +3,17 @@ package com.cf.cs.web;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
/**
* The type Cs web application tests.
*
* @author xajhuang @163.com
*/
@SpringBootTest
class CsWebApplicationTests {
/**
* Context loads.
*/
@Test
void contextLoads() {
}

View File

@ -29,6 +29,7 @@
<module>cs-database</module>
<module>cs-services</module>
<module>cs-web</module>
<module>cs-authentication</module>
<module>cs-restful</module>
</modules>