1. 增加SpringSecurity支持
This commit is contained in:
parent
566074ff21
commit
88f9efb212
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -1,4 +1,4 @@
|
|||
package com.cf.cs.web.interceptor;
|
||||
package com.cf.cs.authentication.interceptor;
|
||||
|
||||
import jakarta.servlet.Filter;
|
||||
import jakarta.servlet.FilterChain;
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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) {
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
}
|
||||
}
|
|
@ -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)
|
|
@ -0,0 +1 @@
|
|||
|
|
|
@ -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() {
|
||||
}
|
||||
|
||||
}
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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),
|
||||
/**
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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() {
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -194,7 +194,7 @@ public class CryptoHelper {
|
|||
}
|
||||
|
||||
/**
|
||||
* Des encryption byte [ ].
|
||||
* Deencryption byte [ ].
|
||||
*
|
||||
* @param plaintext the plaintext
|
||||
* @param desKey the des key
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
// 在组件初始化后执行的逻辑
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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> {
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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的值
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package com.cf.cs.web.configure;
|
||||
package com.cf.cs.restful.configure;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.Getter;
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import org.springframework.stereotype.Component;
|
|||
/**
|
||||
* The type System initial.
|
||||
*
|
||||
* @author xajhuang@163.com
|
||||
* @author xajhuang @163.com
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue