├── .gitignore ├── Dockerfile ├── README.md ├── build.gradle ├── docs ├── images │ ├── 2020-10-22_10-19.png │ ├── 2020-10-22_10-20.png │ └── 2020-10-22_10-29.png └── preview │ ├── login_log.png │ ├── menu_list.png │ ├── profile.png │ ├── role_list.png │ └── workplace.png ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── main ├── java │ └── xyz │ │ └── guqing │ │ └── creek │ │ ├── AppApplication.java │ │ ├── aspect │ │ ├── AbstractAspectSupport.java │ │ └── ControllerEndpointAspect.java │ │ ├── controller │ │ ├── ActionLogController.java │ │ ├── ApiResourceController.java │ │ ├── CredentialsController.java │ │ ├── LoginLogController.java │ │ ├── RoleController.java │ │ ├── SocialLoginController.java │ │ ├── UserController.java │ │ └── UserGroupController.java │ │ ├── converter │ │ └── StringToLocalDateTimeConverter.java │ │ ├── event │ │ └── UserLoginEvent.java │ │ ├── exception │ │ ├── AbstractCreekException.java │ │ ├── AlreadyExistsException.java │ │ ├── AuthenticationException.java │ │ ├── BadArgumentException.java │ │ ├── BadRequestException.java │ │ ├── BeanUtilsException.java │ │ ├── BindSocialAccountException.java │ │ ├── CreekInternalException.java │ │ ├── EmailException.java │ │ ├── FileOperationException.java │ │ ├── ForbiddenException.java │ │ ├── FrequentAccessException.java │ │ ├── MissingPropertyException.java │ │ ├── NotFoundException.java │ │ ├── PropertyFormatException.java │ │ ├── ServiceException.java │ │ ├── UnauthorizedException.java │ │ ├── UnsupportedDataTypeException.java │ │ ├── UnsupportedMediaTypeException.java │ │ └── ValidateCodeException.java │ │ ├── extension │ │ ├── AbstractExtension.java │ │ ├── DefaultExtensionClient.java │ │ ├── Extension.java │ │ ├── ExtensionClient.java │ │ ├── ExtensionConverter.java │ │ ├── ExtensionOperator.java │ │ ├── ExtensionUtil.java │ │ ├── GVK.java │ │ ├── GroupKind.java │ │ ├── GroupVersion.java │ │ ├── GroupVersionKind.java │ │ ├── JSONExtensionConverter.java │ │ ├── Metadata.java │ │ ├── MetadataOperator.java │ │ ├── Scheme.java │ │ ├── Schemes.java │ │ ├── Unstructured.java │ │ ├── exception │ │ │ ├── ExtensionConvertException.java │ │ │ ├── ExtensionException.java │ │ │ ├── SchemaViolationException.java │ │ │ └── SchemeNotFoundException.java │ │ └── store │ │ │ ├── ExtensionStore.java │ │ │ ├── ExtensionStoreClient.java │ │ │ ├── ExtensionStoreClientJPAImpl.java │ │ │ └── ExtensionStoreRepository.java │ │ ├── handler │ │ ├── GlobalExceptionHandler.java │ │ └── SaveUpdateRelatedFieldsMetaHandler.java │ │ ├── identity │ │ ├── apitoken │ │ │ ├── DefaultPersonalAccessTokenDecoder.java │ │ │ ├── PersonalAccessToken.java │ │ │ ├── PersonalAccessTokenAuthenticationToken.java │ │ │ ├── PersonalAccessTokenDecoder.java │ │ │ ├── PersonalAccessTokenException.java │ │ │ ├── PersonalAccessTokenProvider.java │ │ │ ├── PersonalAccessTokenTimestampValidator.java │ │ │ ├── PersonalAccessTokenType.java │ │ │ ├── PersonalAccessTokenUtils.java │ │ │ └── PersonalTokenTypeUtils.java │ │ ├── authentication │ │ │ ├── Context.java │ │ │ ├── DefaultOAuth2TokenContext.java │ │ │ ├── DelegatingAuthenticationConverter.java │ │ │ ├── InMemoryOAuth2AuthorizationService.java │ │ │ ├── JwtGenerator.java │ │ │ ├── OAuth2AccessTokenAuthenticationToken.java │ │ │ ├── OAuth2Authorization.java │ │ │ ├── OAuth2AuthorizationGrantAuthenticationToken.java │ │ │ ├── OAuth2AuthorizationService.java │ │ │ ├── OAuth2EndpointUtils.java │ │ │ ├── OAuth2PasswordAuthenticationConverter.java │ │ │ ├── OAuth2PasswordAuthenticationProvider.java │ │ │ ├── OAuth2PasswordAuthenticationToken.java │ │ │ ├── OAuth2RefreshTokenAuthenticationConverter.java │ │ │ ├── OAuth2RefreshTokenAuthenticationProvider.java │ │ │ ├── OAuth2RefreshTokenAuthenticationToken.java │ │ │ ├── OAuth2TokenContext.java │ │ │ ├── OAuth2TokenEndpointFilter.java │ │ │ ├── OAuth2TokenGenerator.java │ │ │ ├── OAuth2TokenType.java │ │ │ ├── ProviderContext.java │ │ │ ├── ProviderContextFilter.java │ │ │ ├── ProviderContextHolder.java │ │ │ ├── ProviderSettings.java │ │ │ └── verifier │ │ │ │ ├── AbstractOAuth2TokenAuthenticationToken.java │ │ │ │ ├── BearerTokenAuthentication.java │ │ │ │ ├── BearerTokenAuthenticationEntryPoint.java │ │ │ │ ├── BearerTokenAuthenticationFilter.java │ │ │ │ ├── BearerTokenAuthenticationToken.java │ │ │ │ ├── BearerTokenError.java │ │ │ │ ├── BearerTokenErrorCodes.java │ │ │ │ ├── BearerTokenErrors.java │ │ │ │ ├── BearerTokenResolver.java │ │ │ │ ├── DefaultBearerTokenResolver.java │ │ │ │ ├── InvalidBearerTokenException.java │ │ │ │ ├── JwtAuthenticationConverter.java │ │ │ │ ├── JwtAuthenticationProvider.java │ │ │ │ ├── JwtAuthenticationToken.java │ │ │ │ ├── JwtGrantedAuthoritiesConverter.java │ │ │ │ └── JwtProvidedDecoderAuthenticationManagerResolver.java │ │ ├── authorization │ │ │ ├── Attributes.java │ │ │ ├── AttributesRecord.java │ │ │ ├── AuthorizationRuleResolver.java │ │ │ ├── AuthorizingVisitor.java │ │ │ ├── DefaultRoleBindingLister.java │ │ │ ├── DefaultRoleGetter.java │ │ │ ├── DefaultRuleResolver.java │ │ │ ├── PolicyRule.java │ │ │ ├── PolicyRuleList.java │ │ │ ├── RbacRequestEvaluation.java │ │ │ ├── RequestInfo.java │ │ │ ├── RequestInfoAuthorizationManager.java │ │ │ ├── RequestInfoFactory.java │ │ │ ├── ResourceRuleInfo.java │ │ │ ├── Role.java │ │ │ ├── RoleBinding.java │ │ │ ├── RoleBindingLister.java │ │ │ ├── RoleGetter.java │ │ │ ├── RoleRef.java │ │ │ ├── RuleAccumulator.java │ │ │ └── Subject.java │ │ └── entrypoint │ │ │ └── Oauth2LogoutHandler.java │ │ ├── infra │ │ ├── config │ │ │ ├── AbstractSettings.java │ │ │ ├── ConfigurationSettingNames.java │ │ │ ├── WebMvcConfig.java │ │ │ └── WebSecurityConfig.java │ │ ├── properties │ │ │ ├── CreekProperties.java │ │ │ └── JwtProperties.java │ │ └── utils │ │ │ ├── Base62Utils.java │ │ │ ├── JsonUtils.java │ │ │ └── YamlUnstructuredLoader.java │ │ ├── listener │ │ └── UserLoginListener.java │ │ ├── mapper │ │ ├── ActionLogMapper.java │ │ ├── ApiResourceMapper.java │ │ ├── ApiScopeMapper.java │ │ ├── CredentialsMapper.java │ │ ├── MenuMapper.java │ │ ├── OauthAccessTokenMapper.java │ │ ├── OauthRefreshTokenMapper.java │ │ ├── RoleMapper.java │ │ ├── RoleResourceMapper.java │ │ ├── UserConnectionMapper.java │ │ ├── UserGroupMapper.java │ │ ├── UserLoginLogMapper.java │ │ └── UserMapper.java │ │ ├── model │ │ ├── annotation │ │ │ └── ControllerEndpoint.java │ │ ├── bo │ │ │ ├── CurrentUser.java │ │ │ ├── MyUserDetails.java │ │ │ ├── RouterMeta.java │ │ │ └── VueRouter.java │ │ ├── constant │ │ │ ├── CreekConstant.java │ │ │ ├── ImageTypeConstant.java │ │ │ ├── ParamsConstant.java │ │ │ ├── RegexpConstant.java │ │ │ └── StringConstant.java │ │ ├── dos │ │ │ └── UserDO.java │ │ ├── dto │ │ │ ├── ActionLogDTO.java │ │ │ ├── ApiResourceDTO.java │ │ │ ├── ApiScopeDTO.java │ │ │ ├── CredentialsDTO.java │ │ │ ├── MenuDTO.java │ │ │ ├── MenuTree.java │ │ │ ├── RoleDTO.java │ │ │ ├── SimpleRoleDTO.java │ │ │ ├── SocialLoginDTO.java │ │ │ ├── UserDTO.java │ │ │ ├── UserGroupTree.java │ │ │ ├── UserInfoDTO.java │ │ │ └── UserLoginLogDTO.java │ │ ├── entity │ │ │ ├── ActionLog.java │ │ │ ├── ApiResource.java │ │ │ ├── ApiScope.java │ │ │ ├── BaseEntity.java │ │ │ ├── Credentials.java │ │ │ ├── Menu.java │ │ │ ├── OauthAccessToken.java │ │ │ ├── OauthRefreshToken.java │ │ │ ├── Role.java │ │ │ ├── RoleResource.java │ │ │ ├── User.java │ │ │ ├── UserConnection.java │ │ │ ├── UserGroup.java │ │ │ └── UserLoginLog.java │ │ ├── enums │ │ │ ├── GenderEnum.java │ │ │ ├── MenuType.java │ │ │ ├── ResultEntityEnum.java │ │ │ └── UserStatusEnum.java │ │ ├── params │ │ │ ├── ActionLogQuery.java │ │ │ ├── BindUserParam.java │ │ │ ├── ChangePasswordParam.java │ │ │ ├── CredentialsParam.java │ │ │ ├── LoginLogParam.java │ │ │ ├── LoginParam.java │ │ │ ├── MenuParam.java │ │ │ ├── MenuQuery.java │ │ │ ├── RoleParam.java │ │ │ ├── RoleQuery.java │ │ │ ├── SocialUserParam.java │ │ │ ├── UserGroupParam.java │ │ │ ├── UserParam.java │ │ │ ├── UserProfileParam.java │ │ │ └── UserQuery.java │ │ ├── properties │ │ │ └── ThreadPoolProperties.java │ │ └── support │ │ │ ├── BeanUtils.java │ │ │ ├── CreateCheck.java │ │ │ ├── InputConverter.java │ │ │ ├── OutputConverter.java │ │ │ ├── PageInfo.java │ │ │ ├── PageQuery.java │ │ │ ├── ResultEntity.java │ │ │ ├── Tree.java │ │ │ └── UpdateCheck.java │ │ ├── security │ │ ├── handler │ │ │ ├── JwtAccessDeniedHandler.java │ │ │ ├── JwtAuthenticationEntryPoint.java │ │ │ ├── JwtAuthenticationFailureHandler.java │ │ │ └── JwtLogoutSuccessHandler.java │ │ ├── properties │ │ │ ├── LoginProperties.java │ │ │ ├── SecurityProperties.java │ │ │ └── TokenProperties.java │ │ └── support │ │ │ ├── MyUserDetailsServiceImpl.java │ │ │ └── UserLoginService.java │ │ ├── service │ │ ├── ActionLogService.java │ │ ├── ApiResourceService.java │ │ ├── CredentialsService.java │ │ ├── RoleResourceService.java │ │ ├── RoleService.java │ │ ├── UserConnectionService.java │ │ ├── UserGroupService.java │ │ ├── UserLoginLogService.java │ │ ├── UserService.java │ │ └── impl │ │ │ ├── ActionLogServiceImpl.java │ │ │ ├── ApiResourceServiceImpl.java │ │ │ ├── CredentialsServiceImpl.java │ │ │ ├── RoleResourceServiceImpl.java │ │ │ ├── RoleServiceImpl.java │ │ │ ├── UserConnectionServiceImpl.java │ │ │ ├── UserGroupServiceImpl.java │ │ │ ├── UserLoginLogServiceImpl.java │ │ │ └── UserServiceImpl.java │ │ └── utils │ │ ├── CreekUtils.java │ │ ├── DateUtils.java │ │ ├── FilenameUtils.java │ │ ├── PageUtils.java │ │ ├── ReflectionUtils.java │ │ ├── RegionAddressUtils.java │ │ ├── SecurityUserHelper.java │ │ ├── ServiceUtils.java │ │ └── TreeUtil.java └── resources │ ├── app.key │ ├── app.pub │ ├── application.yaml │ ├── db │ ├── data-h2.sql │ └── schema-h2.sql │ ├── ip2region │ └── ip2region.db │ ├── mapper │ └── UserMapper.xml │ ├── static │ ├── assets │ │ ├── background.487d6568.svg │ │ └── logo.73c55b1f.svg │ ├── avatar.png │ ├── css │ │ ├── app.1ee71dc5.css │ │ ├── chunk-20317508.e966bac8.css │ │ ├── chunk-2068754c.1af36cb9.css │ │ ├── chunk-2be72548.42caeaa2.css │ │ ├── chunk-2e3134d4.c59efe83.css │ │ ├── chunk-5c2da618.b6b81657.css │ │ ├── chunk-5e5888e0.fd546ac9.css │ │ ├── chunk-60c3c97d.9642a1cc.css │ │ ├── chunk-70c7a28c.1ea2cfbe.css │ │ ├── chunk-ac0c6ae6.78a6d452.css │ │ ├── chunk-c53a1472.10aa8baa.css │ │ ├── chunk-d2686ecc.6ade1945.css │ │ └── chunk-vendors.0b47211d.css │ ├── icon │ │ ├── alipay.png │ │ ├── dingtalk.png │ │ ├── gitee.png │ │ ├── github.png │ │ ├── microsoft.png │ │ ├── qq.png │ │ ├── taobao.png │ │ ├── tencent_cloud.png │ │ ├── weibo.png │ │ └── weixin.png │ ├── index.html │ ├── js │ │ ├── app.219e52bc.js │ │ ├── chunk-146b91b4.e28e50c2.js │ │ ├── chunk-20317508.ea9996c0.js │ │ ├── chunk-2068754c.ad7bfa4e.js │ │ ├── chunk-2be72548.800da27f.js │ │ ├── chunk-2d0aa1b9.9b738bd3.js │ │ ├── chunk-2d0babff.ff80927a.js │ │ ├── chunk-2d0ded04.f627c320.js │ │ ├── chunk-2d221c57.e35dd895.js │ │ ├── chunk-2e3134d4.f43650d0.js │ │ ├── chunk-5c2da618.c726d1da.js │ │ ├── chunk-5e5888e0.674d7232.js │ │ ├── chunk-60c3c97d.5d1c3969.js │ │ ├── chunk-70c7a28c.1488c580.js │ │ ├── chunk-a3663882.cb2edba3.js │ │ ├── chunk-ac0c6ae6.55d48402.js │ │ ├── chunk-c53a1472.25a46676.js │ │ ├── chunk-d2686ecc.41ef9419.js │ │ ├── chunk-vendors.9050bea6.js │ │ └── lang-zh-CN.8cf88fd4.js │ └── logo.svg │ └── templates │ ├── error.ftl │ └── socialLoginResult.ftl └── test └── java └── xyz └── guqing └── creek ├── CreekApplicationTest.java └── identity ├── apitoken └── PersonalAccessTokenUtilsTest.java └── authentication ├── InMemoryOAuth2AuthorizationServiceTest.java ├── JwtClaimsSetTest.java ├── JwtGeneratorTest.java ├── OAuth2RefreshTokenAuthenticationProviderTest.java ├── ProviderContextFilterTest.java ├── ProviderSettingsTest.java ├── TestOAuth2Authorizations.java └── verifyer ├── BearerTokenAuthenticationTest.java ├── BearerTokenAuthenticationTokenTest.java ├── BearerTokenErrorTest.java ├── BearerTokenErrorsTest.java ├── DefaultBearerTokenResolverTest.java ├── JwtAuthenticationProviderTest.java ├── JwtGrantedAuthoritiesConverterTest.java └── TestJwts.java /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | .gradle 30 | ### VS Code ### 31 | .vscode/ 32 | 33 | .DS_Store 34 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM adoptopenjdk:11-jre-hotspot as builder 2 | WORKDIR /app 3 | ARG JAR_FILE=target/*.jar 4 | COPY ${JAR_FILE} creek.jar 5 | EXPOSE 8086 6 | ENTRYPOINT ["java","-jar","creek.jar"] 7 | -------------------------------------------------------------------------------- /docs/images/2020-10-22_10-19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/docs/images/2020-10-22_10-19.png -------------------------------------------------------------------------------- /docs/images/2020-10-22_10-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/docs/images/2020-10-22_10-20.png -------------------------------------------------------------------------------- /docs/images/2020-10-22_10-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/docs/images/2020-10-22_10-29.png -------------------------------------------------------------------------------- /docs/preview/login_log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/docs/preview/login_log.png -------------------------------------------------------------------------------- /docs/preview/menu_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/docs/preview/menu_list.png -------------------------------------------------------------------------------- /docs/preview/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/docs/preview/profile.png -------------------------------------------------------------------------------- /docs/preview/role_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/docs/preview/role_list.png -------------------------------------------------------------------------------- /docs/preview/workplace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/docs/preview/workplace.png -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | version=1.0.0-SNAPSHOT 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { url 'https://maven.aliyun.com/repository/gradle-plugin' } 4 | maven { url 'https://maven.aliyun.com/repository/spring-plugin' } 5 | maven { url 'https://repo.spring.io/milestone' } 6 | gradlePluginPortal() 7 | } 8 | } 9 | 10 | rootProject.name = 'creek' 11 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/AppApplication.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @SpringBootApplication 8 | @MapperScan("xyz.guqing.creek.mapper") 9 | public class AppApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(AppApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/aspect/AbstractAspectSupport.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.aspect; 2 | 3 | import org.aspectj.lang.ProceedingJoinPoint; 4 | import org.aspectj.lang.reflect.MethodSignature; 5 | 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * @author guqing 10 | * @date 2020-6-1 11 | */ 12 | public abstract class AbstractAspectSupport { 13 | 14 | Method resolveMethod(ProceedingJoinPoint point) { 15 | MethodSignature signature = (MethodSignature) point.getSignature(); 16 | Class targetClass = point.getTarget().getClass(); 17 | 18 | Method method = getDeclaredMethod(targetClass, signature.getName(), 19 | signature.getMethod().getParameterTypes()); 20 | if (method == null) { 21 | throw new IllegalStateException("无法解析目标方法: " + signature.getMethod().getName()); 22 | } 23 | return method; 24 | } 25 | 26 | private Method getDeclaredMethod(Class clazz, String name, Class... parameterTypes) { 27 | try { 28 | return clazz.getDeclaredMethod(name, parameterTypes); 29 | } catch (NoSuchMethodException e) { 30 | Class superClass = clazz.getSuperclass(); 31 | if (superClass != null) { 32 | return getDeclaredMethod(superClass, name, parameterTypes); 33 | } 34 | } 35 | return null; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/controller/ActionLogController.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.controller; 2 | 3 | import com.baomidou.mybatisplus.core.metadata.IPage; 4 | import lombok.RequiredArgsConstructor; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | import xyz.guqing.creek.model.dto.ActionLogDTO; 9 | import xyz.guqing.creek.model.entity.ActionLog; 10 | import xyz.guqing.creek.model.params.ActionLogQuery; 11 | import xyz.guqing.creek.model.support.PageInfo; 12 | import xyz.guqing.creek.model.support.PageQuery; 13 | import xyz.guqing.creek.model.support.ResultEntity; 14 | import xyz.guqing.creek.service.ActionLogService; 15 | 16 | /** 17 | * @author guqing 18 | * @date 2020-07-11 19 | */ 20 | @RestController 21 | @RequiredArgsConstructor 22 | @RequestMapping("/log/action") 23 | public class ActionLogController { 24 | private final ActionLogService actionLogService; 25 | 26 | @GetMapping 27 | public ResultEntity> list(ActionLogQuery actionLogQuery, PageQuery pageQuery) { 28 | IPage actionLogPage = actionLogService.listBy(actionLogQuery,pageQuery); 29 | return ResultEntity.okList(actionLogPage, actionLog -> new ActionLogDTO().convertFrom(actionLog)); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/controller/ApiResourceController.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.controller; 2 | 3 | import java.util.List; 4 | import lombok.AllArgsConstructor; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | import xyz.guqing.creek.model.dto.ApiResourceDTO; 9 | import xyz.guqing.creek.model.support.ResultEntity; 10 | import xyz.guqing.creek.service.ApiResourceService; 11 | 12 | /** 13 | * @author guqing 14 | * @since 2022-01-12 15 | */ 16 | @RestController 17 | @AllArgsConstructor 18 | @RequestMapping("/resources") 19 | public class ApiResourceController { 20 | private final ApiResourceService apiResourceService; 21 | 22 | @GetMapping("/list-view") 23 | public ResultEntity> list() { 24 | List apiResources = apiResourceService.listWithScopes(); 25 | return ResultEntity.ok(apiResources); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/controller/CredentialsController.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.controller; 2 | 3 | import jakarta.validation.Valid; 4 | import java.util.List; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PostMapping; 8 | import org.springframework.web.bind.annotation.RequestBody; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | import xyz.guqing.creek.model.dto.CredentialsDTO; 12 | import xyz.guqing.creek.model.entity.Credentials; 13 | import xyz.guqing.creek.model.params.CredentialsParam; 14 | import xyz.guqing.creek.model.support.ResultEntity; 15 | import xyz.guqing.creek.service.CredentialsService; 16 | 17 | /** 18 | * @author guqing 19 | * @since 2022-01-14 20 | */ 21 | @RestController 22 | @RequestMapping("/credentials") 23 | public class CredentialsController { 24 | 25 | @Autowired 26 | private CredentialsService credentialsService; 27 | 28 | @GetMapping 29 | public ResultEntity> list() { 30 | List results = credentialsService.listAll(); 31 | return ResultEntity.ok(results); 32 | } 33 | 34 | @PostMapping 35 | public ResultEntity create(@RequestBody @Valid CredentialsParam param) { 36 | Credentials credentials = param.convertTo(); 37 | return null; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/controller/LoginLogController.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.controller; 2 | 3 | import com.baomidou.mybatisplus.core.metadata.IPage; 4 | import lombok.RequiredArgsConstructor; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import xyz.guqing.creek.model.dto.UserLoginLogDTO; 10 | import xyz.guqing.creek.model.entity.UserLoginLog; 11 | import xyz.guqing.creek.model.params.LoginLogParam; 12 | import xyz.guqing.creek.model.support.PageInfo; 13 | import xyz.guqing.creek.model.support.PageQuery; 14 | import xyz.guqing.creek.model.support.ResultEntity; 15 | import xyz.guqing.creek.service.UserLoginLogService; 16 | 17 | /** 18 | * @author guqing 19 | * @date 2020-07-17 20 | */ 21 | @Slf4j 22 | @RestController 23 | @RequestMapping("/log/login") 24 | @RequiredArgsConstructor 25 | public class LoginLogController { 26 | private final UserLoginLogService userLoginLogService; 27 | 28 | @GetMapping 29 | public ResultEntity> list(LoginLogParam loginLogParam, PageQuery pageQuery) { 30 | log.debug("登录日志列表参数:[{}]", pageQuery); 31 | IPage userLoginLogs = userLoginLogService.listBy(loginLogParam,pageQuery); 32 | return ResultEntity.okList(userLoginLogs, userLoginLog -> new UserLoginLogDTO().convertFrom(userLoginLog)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/converter/StringToLocalDateTimeConverter.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.converter; 2 | 3 | import org.springframework.core.convert.converter.Converter; 4 | import org.springframework.lang.NonNull; 5 | 6 | import java.time.LocalDateTime; 7 | import java.time.format.DateTimeFormatter; 8 | import java.time.format.DateTimeFormatterBuilder; 9 | import java.time.temporal.ChronoField; 10 | 11 | /** 12 | * @author guqing 13 | * @date 2020-07-16 14 | */ 15 | public class StringToLocalDateTimeConverter implements Converter { 16 | /** 17 | * 构建格式化器,并赋予可选参数默认值,否则会出错 18 | */ 19 | private static final DateTimeFormatter DATE_FORMAT = new DateTimeFormatterBuilder() 20 | .appendPattern("yyyy-MM-dd[ [HH][:mm][:ss][.SSS]]") 21 | .parseDefaulting(ChronoField.HOUR_OF_DAY, 0) 22 | .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0) 23 | .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0) 24 | .toFormatter(); 25 | 26 | @Override 27 | public LocalDateTime convert(@NonNull String s) { 28 | return LocalDateTime.parse(s, DATE_FORMAT); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/event/UserLoginEvent.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.event; 2 | 3 | import org.springframework.context.ApplicationEvent; 4 | 5 | /** 6 | * @author guqing 7 | * @date 2020-06-16 8 | */ 9 | public class UserLoginEvent extends ApplicationEvent { 10 | private String username; 11 | /** 12 | * Create a new {@code ApplicationEvent}. 13 | * 14 | * @param source the object on which the event initially occurred or with 15 | * which the event is associated (never {@code null}) 16 | */ 17 | public UserLoginEvent(Object source, String username) { 18 | super(source); 19 | this.username = username; 20 | } 21 | 22 | public String getUsername() { 23 | return username; 24 | } 25 | 26 | public void setUsername(String username) { 27 | this.username = username; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/AbstractCreekException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.lang.NonNull; 5 | import org.springframework.lang.Nullable; 6 | 7 | /** 8 | * 基类异常 9 | * 10 | * @author guqing 11 | * @date 2020-04-04 16:03 12 | */ 13 | public abstract class AbstractCreekException extends RuntimeException { 14 | /** 15 | * version id 16 | */ 17 | private static final long serialVersionUID = -8889564685896439438L; 18 | 19 | /** 20 | * Error errorData. 21 | */ 22 | private Object errorData; 23 | 24 | public AbstractCreekException(String message) { 25 | super(message); 26 | } 27 | 28 | public AbstractCreekException(String message, Throwable cause) { 29 | super(message, cause); 30 | } 31 | 32 | @NonNull 33 | public abstract HttpStatus getStatus(); 34 | 35 | @Nullable 36 | public Object getErrorData() { 37 | return errorData; 38 | } 39 | 40 | /** 41 | * Sets error errorData. 42 | * 43 | * @param errorData error data 44 | * @return current exception. 45 | */ 46 | @NonNull 47 | public AbstractCreekException setErrorData(@Nullable Object errorData) { 48 | this.errorData = errorData; 49 | return this; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/AlreadyExistsException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | /** 4 | * Exception caused by model existence already. 5 | * 6 | * @author guqing 7 | * @date 2020-4-4 16:29 8 | */ 9 | public class AlreadyExistsException extends BadRequestException { 10 | 11 | private static final long serialVersionUID = -1379001199432321678L; 12 | 13 | public AlreadyExistsException(String message) { 14 | super(message); 15 | } 16 | 17 | public AlreadyExistsException(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/AuthenticationException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | import org.springframework.http.HttpStatus; 4 | 5 | /** 6 | * Authentication exception. 7 | * 8 | * @author guqing 9 | * @date 2020-04-04 16:03 10 | */ 11 | public class AuthenticationException extends AbstractCreekException { 12 | private static final long serialVersionUID = -8823731606051111268L; 13 | 14 | public AuthenticationException(String message) { 15 | super(message); 16 | } 17 | 18 | public AuthenticationException(String message, Throwable cause) { 19 | super(message, cause); 20 | } 21 | 22 | @Override 23 | public HttpStatus getStatus() { 24 | return HttpStatus.UNAUTHORIZED; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/BadArgumentException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | /** 4 | * Exception caused by bad argument. 5 | * 6 | * @author guqing 7 | * @date 2020-07-15 8 | */ 9 | public class BadArgumentException extends BadRequestException { 10 | public BadArgumentException(String message) { 11 | super(message); 12 | } 13 | 14 | public BadArgumentException(String message, Throwable cause) { 15 | super(message, cause); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/BadRequestException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | import org.springframework.http.HttpStatus; 4 | 5 | /** 6 | * Exception caused by bad request. 7 | * 8 | * @author guqing 9 | * @date 2020-04-04 16:03 10 | */ 11 | public class BadRequestException extends AbstractCreekException { 12 | private static final long serialVersionUID = 2888541634229909695L; 13 | 14 | public BadRequestException(String message) { 15 | super(message); 16 | } 17 | 18 | public BadRequestException(String message, Throwable cause) { 19 | super(message, cause); 20 | } 21 | 22 | @Override 23 | public HttpStatus getStatus() { 24 | return HttpStatus.BAD_REQUEST; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/BeanUtilsException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | import org.springframework.http.HttpStatus; 4 | 5 | /** 6 | * BeanUtils exception. 7 | * 8 | * @author johnniang 9 | */ 10 | public class BeanUtilsException extends AbstractCreekException { 11 | 12 | public BeanUtilsException(String message) { 13 | super(message); 14 | } 15 | 16 | public BeanUtilsException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | @Override 21 | public HttpStatus getStatus() { 22 | return HttpStatus.INTERNAL_SERVER_ERROR; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/BindSocialAccountException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.lang.NonNull; 5 | 6 | /** 7 | * @author guqing 8 | * @date 2020-05-07 9 | */ 10 | public class BindSocialAccountException extends AbstractCreekException { 11 | private static final long serialVersionUID = 2170956971483598912L; 12 | 13 | public BindSocialAccountException(String message) { 14 | super(message); 15 | } 16 | 17 | public BindSocialAccountException(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | 21 | @Override 22 | @NonNull 23 | public HttpStatus getStatus() { 24 | return HttpStatus.BAD_GATEWAY; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/CreekInternalException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.lang.NonNull; 5 | 6 | /** 7 | * @author guqing 8 | * @date 2020-06-01 9 | */ 10 | public class CreekInternalException extends AbstractCreekException { 11 | public CreekInternalException(String message) { 12 | super(message); 13 | } 14 | 15 | public CreekInternalException(String message, Throwable cause) { 16 | super(message, cause); 17 | } 18 | 19 | @Override 20 | @NonNull 21 | public HttpStatus getStatus() { 22 | return HttpStatus.INTERNAL_SERVER_ERROR; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/EmailException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | /** 4 | * Email exception. 5 | * 6 | * @author guqing 7 | * @date 2020-04-04 16:03 8 | */ 9 | public class EmailException extends ServiceException { 10 | private static final long serialVersionUID = 8054053086207304307L; 11 | 12 | public EmailException(String message) { 13 | super(message); 14 | } 15 | 16 | public EmailException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/FileOperationException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | /** 4 | * File operation exception. 5 | * 6 | * @author guqing 7 | * @date 2020-04-04 16:03 8 | */ 9 | public class FileOperationException extends ServiceException { 10 | private static final long serialVersionUID = 3171412351360260518L; 11 | 12 | public FileOperationException(String message) { 13 | super(message); 14 | } 15 | 16 | public FileOperationException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/ForbiddenException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | import org.springframework.http.HttpStatus; 4 | 5 | /** 6 | * Exception caused by accessing forbidden resources. 7 | * 8 | * @author guqing 9 | * @date 2020-04-04 16:03 10 | */ 11 | public class ForbiddenException extends AbstractCreekException { 12 | private static final long serialVersionUID = 7685019181203066845L; 13 | 14 | public ForbiddenException(String message) { 15 | super(message); 16 | } 17 | 18 | public ForbiddenException(String message, Throwable cause) { 19 | super(message, cause); 20 | } 21 | 22 | @Override 23 | public HttpStatus getStatus() { 24 | return HttpStatus.FORBIDDEN; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/FrequentAccessException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | /** 4 | * Frequent access exception. 5 | * 6 | * @author guqing 7 | * @date 2020-04-04 16:03 8 | */ 9 | public class FrequentAccessException extends BadRequestException { 10 | private static final long serialVersionUID = 1947535783596017366L; 11 | 12 | public FrequentAccessException(String message) { 13 | super(message); 14 | } 15 | 16 | public FrequentAccessException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/MissingPropertyException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | /** 4 | * Missing property value exception. 5 | * 6 | * @author guqing 7 | * @date 2020-04-04 16:03 8 | */ 9 | public class MissingPropertyException extends BadRequestException { 10 | private static final long serialVersionUID = 1932212946514588758L; 11 | 12 | public MissingPropertyException(String message) { 13 | super(message); 14 | } 15 | 16 | public MissingPropertyException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/NotFoundException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | import org.springframework.http.HttpStatus; 4 | 5 | /** 6 | * Exception of model not found. 7 | * 8 | * @author guqing 9 | * @date 2020-04-04 16:03 10 | */ 11 | public class NotFoundException extends AbstractCreekException { 12 | private static final long serialVersionUID = -2218664015213932183L; 13 | 14 | public NotFoundException(String message) { 15 | super(message); 16 | } 17 | 18 | public NotFoundException(String message, Throwable cause) { 19 | super(message, cause); 20 | } 21 | 22 | @Override 23 | public HttpStatus getStatus() { 24 | return HttpStatus.NOT_FOUND; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/PropertyFormatException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | /** 4 | * Property format exception. 5 | * 6 | * @author guqing 7 | * @date 2020-04-04 16:03 8 | */ 9 | public class PropertyFormatException extends BadRequestException { 10 | private static final long serialVersionUID = 5427803241943272018L; 11 | 12 | public PropertyFormatException(String message) { 13 | super(message); 14 | } 15 | 16 | public PropertyFormatException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/ServiceException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | import org.springframework.http.HttpStatus; 4 | 5 | /** 6 | * Exception caused by service. 7 | * 8 | * @author guqing 9 | * @date 2020-04-04 16:03 10 | */ 11 | public class ServiceException extends AbstractCreekException { 12 | private static final long serialVersionUID = 4732689741650548040L; 13 | 14 | public ServiceException(String message) { 15 | super(message); 16 | } 17 | 18 | public ServiceException(String message, Throwable cause) { 19 | super(message, cause); 20 | } 21 | 22 | @Override 23 | public HttpStatus getStatus() { 24 | return HttpStatus.INTERNAL_SERVER_ERROR; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/UnauthorizedException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | import org.springframework.http.HttpStatus; 4 | 5 | /** 6 | * 未授权异常 7 | * @author guqing 8 | * @date 2020-09-02 9 | */ 10 | public class UnauthorizedException extends AbstractCreekException { 11 | private static final long serialVersionUID = 7685019181203066845L; 12 | 13 | public UnauthorizedException(String message) { 14 | super(message); 15 | } 16 | 17 | public UnauthorizedException(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | 21 | @Override 22 | public HttpStatus getStatus() { 23 | return HttpStatus.FORBIDDEN; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/UnsupportedDataTypeException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | /** 4 | * @author guqing 5 | * @date 2020-04-15 11:17 6 | */ 7 | public class UnsupportedDataTypeException extends BadRequestException { 8 | private static final long serialVersionUID = 7932950060225121991L; 9 | 10 | public UnsupportedDataTypeException(String message) { 11 | super(message); 12 | } 13 | 14 | public UnsupportedDataTypeException(String message, Throwable cause) { 15 | super(message, cause); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/UnsupportedMediaTypeException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | /** 4 | * Unsupported media type exception. 5 | * 6 | * @author guqing 7 | * @date 2020-04-04 16:03 8 | */ 9 | public class UnsupportedMediaTypeException extends BadRequestException { 10 | private static final long serialVersionUID = 503164471927700820L; 11 | 12 | public UnsupportedMediaTypeException(String message) { 13 | super(message); 14 | } 15 | 16 | public UnsupportedMediaTypeException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/exception/ValidateCodeException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.exception; 2 | 3 | /** 4 | * 验证码类型异常 5 | * 6 | * @author MrBird 7 | */ 8 | public class ValidateCodeException extends Exception { 9 | 10 | private static final long serialVersionUID = 7514854456967620043L; 11 | 12 | public ValidateCodeException(String message) { 13 | super(message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/extension/AbstractExtension.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.extension; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * AbstractExtension contains basic structure of Extension and implements the Extension interface. 7 | * 8 | * @author johnniang 9 | */ 10 | @Data 11 | public abstract class AbstractExtension implements Extension { 12 | 13 | private String apiVersion; 14 | 15 | private String kind; 16 | 17 | private MetadataOperator metadata; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/extension/Extension.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.extension; 2 | 3 | /** 4 | * Extension is an interface which represents an Extension. It contains setters and getters of 5 | * GroupVersionKind and Metadata. 6 | */ 7 | public interface Extension extends ExtensionOperator { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/extension/ExtensionConverter.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.extension; 2 | 3 | import xyz.guqing.creek.extension.store.ExtensionStore; 4 | 5 | /** 6 | * ExtensionConverter contains bidirectional conversions between Extension and ExtensionStore. 7 | * 8 | * @author johnniang 9 | */ 10 | public interface ExtensionConverter { 11 | 12 | /** 13 | * Converts Extension to ExtensionStore. 14 | * 15 | * @param extension is an Extension to be converted. 16 | * @param is Extension type. 17 | * @return an ExtensionStore. 18 | */ 19 | ExtensionStore convertTo(E extension); 20 | 21 | /** 22 | * Converts Extension from ExtensionStore. 23 | * 24 | * @param type is Extension type. 25 | * @param extensionStore is an ExtensionStore 26 | * @param is Extension type. 27 | * @return an Extension 28 | */ 29 | E convertFrom(Class type, ExtensionStore extensionStore); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/extension/ExtensionUtil.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.extension; 2 | 3 | import org.springframework.util.StringUtils; 4 | 5 | /** 6 | * Extension utilities. 7 | * 8 | * @author johnniang 9 | */ 10 | public final class ExtensionUtil { 11 | 12 | private ExtensionUtil() { 13 | } 14 | 15 | /** 16 | * Builds the name prefix of ExtensionStore. 17 | * 18 | * @param scheme is scheme of an Extension. 19 | * @return name prefix of ExtensionStore. 20 | */ 21 | public static String buildStoreNamePrefix(Scheme scheme) { 22 | // rule of key: /registry/[group]/plural-name/extension-name 23 | StringBuilder builder = new StringBuilder("/registry/"); 24 | if (StringUtils.hasText(scheme.groupVersionKind().group())) { 25 | builder.append(scheme.groupVersionKind().group()).append('/'); 26 | } 27 | builder.append(scheme.plural()); 28 | return builder.toString(); 29 | } 30 | 31 | /** 32 | * Builds full name of ExtensionStore. 33 | * 34 | * @param scheme is scheme of an Extension. 35 | * @param name the exact name of Extension. 36 | * @return full name of ExtensionStore. 37 | */ 38 | public static String buildStoreName(Scheme scheme, String name) { 39 | return buildStoreNamePrefix(scheme) + "/" + name; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/extension/GVK.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.extension; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * GVK is an annotation to specific metadata of Extension. 10 | * 11 | * @author johnniang 12 | */ 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target(ElementType.TYPE) 15 | public @interface GVK { 16 | 17 | /** 18 | * @return group name of Extension. 19 | */ 20 | String group(); 21 | 22 | /** 23 | * @return version name of Extension. 24 | */ 25 | String version(); 26 | 27 | /** 28 | * @return kind name of Extension. 29 | */ 30 | String kind(); 31 | 32 | /** 33 | * @return plural name of Extension. 34 | */ 35 | String plural(); 36 | 37 | /** 38 | * @return singular name of Extension. 39 | */ 40 | String singular(); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/extension/GroupKind.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.extension; 2 | 3 | /** 4 | * GroupKind contains group and kind data only. 5 | * 6 | * @param group is group name of Extension. 7 | * @param kind is kind name of Extension. 8 | * @author johnniang 9 | */ 10 | public record GroupKind(String group, String kind) { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/extension/GroupVersion.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.extension; 2 | 3 | import org.springframework.util.Assert; 4 | import org.springframework.util.StringUtils; 5 | 6 | /** 7 | * GroupVersion contains group and version name of an Extension only. 8 | * 9 | * @param group is group name of Extension. 10 | * @param version is version name of Extension. 11 | * @author johnniang 12 | */ 13 | public record GroupVersion(String group, String version) { 14 | 15 | @Override 16 | public String toString() { 17 | return StringUtils.hasText(group) ? group + "/" + version : version; 18 | } 19 | 20 | /** 21 | * Parses APIVersion into GroupVersion record. 22 | * 23 | * @param apiVersion must not be blank. 24 | * 1. If the given apiVersion does not contain any "/", we treat the group is empty. 25 | * 2. If the given apiVersion contains more than 1 "/", we will throw an 26 | * IllegalArgumentException. 27 | * @return record contains group and version. 28 | */ 29 | public static GroupVersion parseAPIVersion(String apiVersion) { 30 | Assert.hasText(apiVersion, "API version must not be blank"); 31 | 32 | var groupVersion = apiVersion.split("/"); 33 | return switch (groupVersion.length) { 34 | case 1 -> new GroupVersion("", apiVersion); 35 | case 2 -> new GroupVersion(groupVersion[0], groupVersion[1]); 36 | default -> 37 | throw new IllegalArgumentException("Unexpected APIVersion string: " + apiVersion); 38 | }; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/extension/GroupVersionKind.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.extension; 2 | 3 | import org.springframework.util.Assert; 4 | 5 | /** 6 | * GroupVersionKind contains group, version and kind name of an Extension. 7 | * 8 | * @param group is group name of Extension. 9 | * @param version is version name of Extension. 10 | * @param kind is kind name of Extension. 11 | * @author johnniang 12 | */ 13 | public record GroupVersionKind(String group, String version, String kind) { 14 | 15 | public GroupVersionKind { 16 | Assert.hasText(version, "Version must not be blank"); 17 | Assert.hasText(kind, "Kind must not be blank"); 18 | } 19 | 20 | /** 21 | * Gets group and version name of Extension. 22 | * 23 | * @return group and version name of Extension. 24 | */ 25 | public GroupVersion groupVersion() { 26 | return new GroupVersion(group, version); 27 | } 28 | 29 | /** 30 | * Composes GroupVersionKind from API version and kind name. 31 | * 32 | * @param apiVersion is API version. Like "core.halo.run/v1alpha1" 33 | * @param kind is kind name of Extension. 34 | * @return GroupVersionKind of an Extension. 35 | */ 36 | public static GroupVersionKind fromAPIVersionAndKind(String apiVersion, String kind) { 37 | Assert.hasText(kind, "Kind must not be blank"); 38 | 39 | var gv = GroupVersion.parseAPIVersion(apiVersion); 40 | return new GroupVersionKind(gv.group(), gv.version(), kind); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/extension/Metadata.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.extension; 2 | 3 | import java.time.Instant; 4 | import java.util.Map; 5 | import lombok.Data; 6 | 7 | /** 8 | * Metadata of Extension. 9 | * 10 | * @author johnniang 11 | */ 12 | @Data 13 | public class Metadata implements MetadataOperator { 14 | 15 | /** 16 | * Metadata name. The name is unique globally. 17 | */ 18 | private String name; 19 | 20 | /** 21 | * Labels are like key-value format. 22 | */ 23 | private Map labels; 24 | 25 | /** 26 | * Annotations are like key-value format. 27 | */ 28 | private Map annotations; 29 | 30 | /** 31 | * Current version of the Extension. It will be bumped up every update. 32 | */ 33 | private Long version; 34 | 35 | /** 36 | * Creation timestamp of the Extension. 37 | */ 38 | private Instant creationTimestamp; 39 | 40 | /** 41 | * Deletion timestamp of the Extension. 42 | */ 43 | private Instant deletionTimestamp; 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/extension/MetadataOperator.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.extension; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 5 | import io.swagger.v3.oas.annotations.media.Schema; 6 | import java.time.Instant; 7 | import java.util.Map; 8 | 9 | /** 10 | * MetadataOperator contains some getters and setters for required fields of metadata. 11 | * 12 | * @author johnniang 13 | */ 14 | @JsonDeserialize(as = Metadata.class) 15 | @Schema(implementation = Metadata.class) 16 | public interface MetadataOperator { 17 | 18 | @Schema(required = true) 19 | @JsonProperty("name") 20 | String getName(); 21 | 22 | @Schema(nullable = true) 23 | @JsonProperty("labels") 24 | Map getLabels(); 25 | 26 | @Schema(nullable = true) 27 | @JsonProperty("annotations") 28 | Map getAnnotations(); 29 | 30 | @Schema(nullable = true) 31 | @JsonProperty("version") 32 | Long getVersion(); 33 | 34 | @Schema(nullable = true) 35 | @JsonProperty("creationTimestamp") 36 | Instant getCreationTimestamp(); 37 | 38 | @Schema(nullable = true) 39 | @JsonProperty("deletionTimestamp") 40 | Instant getDeletionTimestamp(); 41 | 42 | void setName(String name); 43 | 44 | void setLabels(Map labels); 45 | 46 | void setAnnotations(Map annotations); 47 | 48 | void setVersion(Long version); 49 | 50 | void setCreationTimestamp(Instant creationTimestamp); 51 | 52 | void setDeletionTimestamp(Instant deletionTimestamp); 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/extension/Scheme.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.extension; 2 | 3 | import com.fasterxml.jackson.databind.node.ObjectNode; 4 | import org.springframework.util.Assert; 5 | 6 | /** 7 | * This class represents scheme of an Extension. 8 | * 9 | * @param type is Extension type. 10 | * @param groupVersionKind is GroupVersionKind of Extension. 11 | * @param plural is plural name of Extension. 12 | * @param singular is singular name of Extension. 13 | * @param jsonSchema is JSON schema of Extension. 14 | * @author johnniang 15 | */ 16 | public record Scheme(Class type, 17 | GroupVersionKind groupVersionKind, 18 | String plural, 19 | String singular, 20 | ObjectNode jsonSchema) { 21 | public Scheme { 22 | Assert.notNull(type, "Type of Extension must not be null"); 23 | Assert.notNull(groupVersionKind, "GroupVersionKind of Extension must not be null"); 24 | Assert.hasText(plural, "Plural name of Extension must not be blank"); 25 | Assert.hasText(singular, "Singular name of Extension must not be blank"); 26 | Assert.notNull(jsonSchema, "Json Schema must not be null"); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/extension/exception/ExtensionConvertException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.extension.exception; 2 | 3 | /** 4 | * ExtensionConvertException is thrown when an Extension conversion error occurs. 5 | * 6 | * @author johnniang 7 | */ 8 | public class ExtensionConvertException extends ExtensionException { 9 | 10 | public ExtensionConvertException() { 11 | } 12 | 13 | public ExtensionConvertException(String message) { 14 | super(message); 15 | } 16 | 17 | public ExtensionConvertException(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | 21 | public ExtensionConvertException(Throwable cause) { 22 | super(cause); 23 | } 24 | 25 | public ExtensionConvertException(String message, Throwable cause, boolean enableSuppression, 26 | boolean writableStackTrace) { 27 | super(message, cause, enableSuppression, writableStackTrace); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/extension/exception/ExtensionException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.extension.exception; 2 | 3 | /** 4 | * ExtensionException is the superclass of those exceptions that can be thrown by Extension module. 5 | * 6 | * @author johnniang 7 | */ 8 | public class ExtensionException extends RuntimeException { 9 | 10 | public ExtensionException() { 11 | } 12 | 13 | public ExtensionException(String message) { 14 | super(message); 15 | } 16 | 17 | public ExtensionException(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | 21 | public ExtensionException(Throwable cause) { 22 | super(cause); 23 | } 24 | 25 | public ExtensionException(String message, Throwable cause, boolean enableSuppression, 26 | boolean writableStackTrace) { 27 | super(message, cause, enableSuppression, writableStackTrace); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/extension/exception/SchemaViolationException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.extension.exception; 2 | 3 | import com.networknt.schema.ValidationMessage; 4 | import java.util.Set; 5 | 6 | /** 7 | * This exception is thrown when Schema is violation. 8 | * 9 | * @author johnniang 10 | */ 11 | public class SchemaViolationException extends ExtensionException { 12 | 13 | /** 14 | * Validation errors. 15 | */ 16 | private final Set errors; 17 | 18 | public SchemaViolationException(Set errors) { 19 | this.errors = errors; 20 | } 21 | 22 | public SchemaViolationException(String message, Set errors) { 23 | super(message); 24 | this.errors = errors; 25 | } 26 | 27 | public SchemaViolationException(String message, Throwable cause, 28 | Set errors) { 29 | super(message, cause); 30 | this.errors = errors; 31 | } 32 | 33 | public SchemaViolationException(Throwable cause, Set errors) { 34 | super(cause); 35 | this.errors = errors; 36 | } 37 | 38 | public SchemaViolationException(String message, Throwable cause, boolean enableSuppression, 39 | boolean writableStackTrace, Set errors) { 40 | super(message, cause, enableSuppression, writableStackTrace); 41 | this.errors = errors; 42 | } 43 | 44 | public Set getErrors() { 45 | return errors; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/extension/exception/SchemeNotFoundException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.extension.exception; 2 | 3 | /** 4 | * SchemeNotFoundException is thrown while we try to get a scheme but not found. 5 | * 6 | * @author johnniang 7 | */ 8 | public class SchemeNotFoundException extends ExtensionException { 9 | 10 | public SchemeNotFoundException() { 11 | } 12 | 13 | public SchemeNotFoundException(String message) { 14 | super(message); 15 | } 16 | 17 | public SchemeNotFoundException(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | 21 | public SchemeNotFoundException(Throwable cause) { 22 | super(cause); 23 | } 24 | 25 | public SchemeNotFoundException(String message, Throwable cause, boolean enableSuppression, 26 | boolean writableStackTrace) { 27 | super(message, cause, enableSuppression, writableStackTrace); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/extension/store/ExtensionStore.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.extension.store; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.Id; 5 | import jakarta.persistence.Lob; 6 | import jakarta.persistence.Version; 7 | import lombok.Data; 8 | 9 | /** 10 | * ExtensionStore is an entity for storing Extension data into database. 11 | * 12 | * @author johnniang 13 | */ 14 | @Data 15 | @Entity(name = "extensions") 16 | public class ExtensionStore { 17 | 18 | /** 19 | * Extension store name, which is globally unique. 20 | * We will use it to query Extensions by using left-like query clause. 21 | */ 22 | @Id 23 | private String name; 24 | 25 | /** 26 | * Exactly Extension body, which might be base64 format. 27 | */ 28 | @Lob 29 | private byte[] data; 30 | 31 | /** 32 | * This field only for serving optimistic lock value. 33 | */ 34 | @Version 35 | private Long version; 36 | 37 | public ExtensionStore() { 38 | } 39 | 40 | public ExtensionStore(String name, byte[] data) { 41 | this.name = name; 42 | this.data = data; 43 | } 44 | 45 | public ExtensionStore(String name, Long version) { 46 | this.name = name; 47 | this.version = version; 48 | } 49 | 50 | public ExtensionStore(String name, byte[] data, Long version) { 51 | this.name = name; 52 | this.data = data; 53 | this.version = version; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/extension/store/ExtensionStoreClient.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.extension.store; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | 6 | /** 7 | * An interface to query and operate ExtensionStore. 8 | * 9 | * @author johnniang 10 | */ 11 | public interface ExtensionStoreClient { 12 | 13 | /** 14 | * Lists all ExtensionStores by name prefix. 15 | * 16 | * @param prefix is the prefix of ExtensionStore name. 17 | * @return all ExtensionStores which names start with the prefix. 18 | */ 19 | List listByNamePrefix(String prefix); 20 | 21 | /** 22 | * Fetches an ExtensionStore by unique name. 23 | * 24 | * @param name is the full name of an ExtensionStore. 25 | * @return an optional ExtensionStore. 26 | */ 27 | Optional fetchByName(String name); 28 | 29 | /** 30 | * Creates an ExtensionStore. 31 | * 32 | * @param name is the full name of an ExtensionStore. 33 | * @param data is Extension body to be persisted. 34 | * @return a fresh ExtensionStore created just now. 35 | */ 36 | ExtensionStore create(String name, byte[] data); 37 | 38 | /** 39 | * Updates an ExtensionStore with version to prevent concurrent update. 40 | * 41 | * @param name is the full name of an ExtensionStore. 42 | * @param version is the expected version of ExtensionStore. 43 | * @param data is Extension body to be updated. 44 | * @return updated ExtensionStore with a fresh version. 45 | */ 46 | ExtensionStore update(String name, Long version, byte[] data); 47 | 48 | /** 49 | * Deletes an ExtensionStore by name and current version. 50 | * 51 | * @param name is the full name of an ExtensionStore. 52 | * @param version is the expected version of ExtensionStore. 53 | * @return previous ExtensionStore. 54 | */ 55 | ExtensionStore delete(String name, Long version); 56 | 57 | //TODO add watch method here. 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/extension/store/ExtensionStoreClientJPAImpl.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.extension.store; 2 | 3 | import jakarta.persistence.EntityNotFoundException; 4 | import java.util.List; 5 | import java.util.Optional; 6 | import org.springframework.stereotype.Service; 7 | 8 | /** 9 | * An implementation of ExtensionStoreClient using JPA. 10 | * 11 | * @author johnniang 12 | */ 13 | @Service 14 | public class ExtensionStoreClientJPAImpl implements ExtensionStoreClient { 15 | 16 | private final ExtensionStoreRepository repository; 17 | 18 | public ExtensionStoreClientJPAImpl(ExtensionStoreRepository repository) { 19 | this.repository = repository; 20 | } 21 | 22 | @Override 23 | public List listByNamePrefix(String prefix) { 24 | return repository.findAllByNameStartingWith(prefix); 25 | } 26 | 27 | @Override 28 | public Optional fetchByName(String name) { 29 | return repository.findById(name); 30 | } 31 | 32 | @Override 33 | public ExtensionStore create(String name, byte[] data) { 34 | var store = new ExtensionStore(name, data); 35 | return repository.save(store); 36 | } 37 | 38 | @Override 39 | public ExtensionStore update(String name, Long version, byte[] data) { 40 | var store = new ExtensionStore(name, data, version); 41 | return repository.save(store); 42 | } 43 | 44 | @Override 45 | public ExtensionStore delete(String name, Long version) { 46 | var extensionStore = 47 | repository.findById(name).orElseThrow(EntityNotFoundException::new); 48 | extensionStore.setVersion(version); 49 | repository.delete(extensionStore); 50 | return extensionStore; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/extension/store/ExtensionStoreRepository.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.extension.store; 2 | 3 | import java.util.List; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | /** 8 | * This repository contains some basic operations on ExtensionStore entity. 9 | * 10 | * @author johnniang 11 | */ 12 | @Repository 13 | public interface ExtensionStoreRepository extends JpaRepository { 14 | 15 | /** 16 | * Finds all ExtensionStore by name prefix. 17 | * 18 | * @param prefix is the prefix of name. 19 | * @return all ExtensionStores which names starts with the given prefix. 20 | */ 21 | List findAllByNameStartingWith(String prefix); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/handler/SaveUpdateRelatedFieldsMetaHandler.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.handler; 2 | 3 | import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; 4 | import org.apache.ibatis.reflection.MetaObject; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | /** 10 | * @author guqing 11 | * @date 2020-04-09 14:01 12 | */ 13 | @Configuration 14 | public class SaveUpdateRelatedFieldsMetaHandler implements MetaObjectHandler { 15 | 16 | /** 17 | * 插入操作自动填充 18 | */ 19 | @Override 20 | public void insertFill(MetaObject metaObject) { 21 | this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); 22 | this.strictInsertFill(metaObject, "modifyTime", LocalDateTime.class, LocalDateTime.now()); 23 | } 24 | 25 | /** 26 | * 更新操作自动填充 27 | */ 28 | @Override 29 | public void updateFill(MetaObject metaObject) { 30 | this.strictUpdateFill(metaObject, "modifyTime", LocalDateTime.class, LocalDateTime.now()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/apitoken/PersonalAccessTokenDecoder.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.apitoken; 2 | 3 | /** 4 | * @author guqing 5 | * @since 2.0.0 6 | */ 7 | public interface PersonalAccessTokenDecoder { 8 | 9 | PersonalAccessToken decode(String token) throws PersonalAccessTokenException; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/apitoken/PersonalAccessTokenException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.apitoken; 2 | 3 | /** 4 | * Base exception for all personal access token related errors. 5 | * 6 | * @author guqing 7 | * @since 2.0.0 8 | */ 9 | public class PersonalAccessTokenException extends RuntimeException { 10 | 11 | public PersonalAccessTokenException(String message) { 12 | super(message); 13 | } 14 | 15 | public PersonalAccessTokenException(String message, Throwable cause) { 16 | super(message, cause); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/apitoken/PersonalAccessTokenType.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.apitoken; 2 | 3 | import org.springframework.util.Assert; 4 | 5 | /** 6 | *

Personal access token type.

7 | * 8 | * @author guqing 9 | * @since 2.0.0 10 | */ 11 | public record PersonalAccessTokenType(String value) { 12 | 13 | public static final PersonalAccessTokenType ADMIN_TOKEN = new PersonalAccessTokenType("ha"); 14 | public static final PersonalAccessTokenType CONTENT_TOKEN = new PersonalAccessTokenType("hc"); 15 | 16 | /** 17 | * Constructs an {@code PersonalAccessTokenType} using the provided value. 18 | * 19 | * @param value the value of the token type 20 | */ 21 | public PersonalAccessTokenType { 22 | Assert.hasText(value, "value cannot be empty"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authentication/Context.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authentication; 2 | 3 | import org.springframework.lang.Nullable; 4 | import org.springframework.util.Assert; 5 | 6 | /** 7 | * A facility for holding information associated to a specific context. 8 | * 9 | * @author guqing 10 | * @since 2.0.0 11 | */ 12 | public interface Context { 13 | /** 14 | * Returns the value of the attribute associated to the key. 15 | * 16 | * @param key the key for the attribute 17 | * @param the type of the value for the attribute 18 | * @return the value of the attribute associated to the key, or {@code null} if not available 19 | */ 20 | @Nullable 21 | V get(Object key); 22 | 23 | /** 24 | * Returns the value of the attribute associated to the key. 25 | * 26 | * @param key the key for the attribute 27 | * @param the type of the value for the attribute 28 | * @return the value of the attribute associated to the key, or {@code null} if not available 29 | * or not of the specified type 30 | */ 31 | @Nullable 32 | default V get(Class key) { 33 | Assert.notNull(key, "key cannot be null"); 34 | V value = get((Object) key); 35 | return key.isInstance(value) ? value : null; 36 | } 37 | 38 | /** 39 | * Returns {@code true} if an attribute associated to the key exists, {@code false} otherwise. 40 | * 41 | * @param key the key for the attribute 42 | * @return {@code true} if an attribute associated to the key exists, {@code false} otherwise 43 | */ 44 | boolean hasKey(Object key); 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authentication/DefaultOAuth2TokenContext.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authentication; 2 | 3 | import java.util.Map; 4 | import org.springframework.lang.Nullable; 5 | import org.springframework.util.Assert; 6 | 7 | /** 8 | * Default implementation of {@link OAuth2TokenContext}. 9 | * 10 | * @author guqing 11 | * @since 2.0.0 12 | */ 13 | public record DefaultOAuth2TokenContext(Map context) implements OAuth2TokenContext { 14 | public DefaultOAuth2TokenContext { 15 | context = Map.copyOf(context); 16 | } 17 | 18 | @SuppressWarnings("unchecked") 19 | @Nullable 20 | @Override 21 | public V get(Object key) { 22 | return hasKey(key) ? (V) this.context.get(key) : null; 23 | } 24 | 25 | @Override 26 | public boolean hasKey(Object key) { 27 | Assert.notNull(key, "key cannot be null"); 28 | return this.context.containsKey(key); 29 | } 30 | 31 | /** 32 | * Returns a new {@link Builder}. 33 | * 34 | * @return the {@link Builder} 35 | */ 36 | public static Builder builder() { 37 | return new Builder(); 38 | } 39 | 40 | /** 41 | * A builder for {@link DefaultOAuth2TokenContext}. 42 | */ 43 | public static final class Builder extends AbstractBuilder { 44 | 45 | private Builder() { 46 | } 47 | 48 | /** 49 | * Builds a new {@link DefaultOAuth2TokenContext}. 50 | * 51 | * @return the {@link DefaultOAuth2TokenContext} 52 | */ 53 | public DefaultOAuth2TokenContext build() { 54 | return new DefaultOAuth2TokenContext(getContext()); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authentication/DelegatingAuthenticationConverter.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authentication; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import java.util.Collections; 5 | import java.util.LinkedList; 6 | import java.util.List; 7 | import org.springframework.lang.Nullable; 8 | import org.springframework.security.core.Authentication; 9 | import org.springframework.security.web.authentication.AuthenticationConverter; 10 | import org.springframework.util.Assert; 11 | 12 | /** 13 | * An {@link AuthenticationConverter} that simply delegates to it's 14 | * internal {@code List} of {@link AuthenticationConverter}(s). 15 | *

16 | * Each {@link AuthenticationConverter} is given a chance to 17 | * {@link AuthenticationConverter#convert(HttpServletRequest)} 18 | * with the first {@code non-null} {@link Authentication} being returned. 19 | * 20 | * @author guqing 21 | * @see AuthenticationConverter 22 | * @since 2.0.0 23 | */ 24 | public class DelegatingAuthenticationConverter implements AuthenticationConverter { 25 | private final List converters; 26 | 27 | /** 28 | * Constructs a {@code DelegatingAuthenticationConverter} using the provided parameters. 29 | * 30 | * @param converters a {@code List} of {@link AuthenticationConverter}(s) 31 | */ 32 | public DelegatingAuthenticationConverter(List converters) { 33 | Assert.notEmpty(converters, "converters cannot be empty"); 34 | this.converters = Collections.unmodifiableList(new LinkedList<>(converters)); 35 | } 36 | 37 | @Nullable 38 | @Override 39 | public Authentication convert(HttpServletRequest request) { 40 | Assert.notNull(request, "request cannot be null"); 41 | for (AuthenticationConverter converter : this.converters) { 42 | Authentication authentication = converter.convert(request); 43 | if (authentication != null) { 44 | return authentication; 45 | } 46 | } 47 | return null; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authentication/OAuth2AuthorizationService.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authentication; 2 | 3 | import org.springframework.lang.Nullable; 4 | 5 | /** 6 | * @author guqing 7 | * @since 2.0.0 8 | */ 9 | public interface OAuth2AuthorizationService { 10 | /** 11 | * Returns the {@link OAuth2Authorization} containing the provided {@code token}, 12 | * or {@code null} if not found. 13 | * 14 | * @param token the token credential 15 | * @param tokenType the {@link OAuth2TokenType token type} 16 | * @return the {@link OAuth2Authorization} if found, otherwise {@code null} 17 | */ 18 | @Nullable 19 | OAuth2Authorization findByToken(String token, @Nullable OAuth2TokenType tokenType); 20 | 21 | /** 22 | * Saves the {@link OAuth2Authorization}. 23 | * 24 | * @param authorization the {@link OAuth2Authorization} 25 | */ 26 | void save(OAuth2Authorization authorization); 27 | 28 | /** 29 | * Removes the {@link OAuth2Authorization}. 30 | * 31 | * @param authorization the {@link OAuth2Authorization} 32 | */ 33 | void remove(OAuth2Authorization authorization); 34 | 35 | /** 36 | * Returns the {@link OAuth2Authorization} identified by the provided {@code id}, 37 | * or {@code null} if not found. 38 | * 39 | * @param id the authorization identifier 40 | * @return the {@link OAuth2Authorization} if found, otherwise {@code null} 41 | */ 42 | @Nullable 43 | OAuth2Authorization findById(String id); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authentication/OAuth2EndpointUtils.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authentication; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import java.util.Map; 5 | import org.springframework.security.oauth2.core.OAuth2AuthenticationException; 6 | import org.springframework.security.oauth2.core.OAuth2Error; 7 | import org.springframework.util.LinkedMultiValueMap; 8 | import org.springframework.util.MultiValueMap; 9 | 10 | /** 11 | * @author guqing 12 | * @since 2.0.0 13 | */ 14 | public class OAuth2EndpointUtils { 15 | static final String ERROR_URI = 16 | "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2"; 17 | 18 | static MultiValueMap getParameters(HttpServletRequest request) { 19 | Map parameterMap = request.getParameterMap(); 20 | MultiValueMap parameters = new LinkedMultiValueMap<>(parameterMap.size()); 21 | parameterMap.forEach((key, values) -> { 22 | if (values.length > 0) { 23 | for (String value : values) { 24 | parameters.add(key, value); 25 | } 26 | } 27 | }); 28 | return parameters; 29 | } 30 | 31 | static void throwError(String errorCode, String parameterName, String errorUri) { 32 | OAuth2Error 33 | error = new OAuth2Error(errorCode, "OAuth 2.0 Parameter: " + parameterName, errorUri); 34 | throw new OAuth2AuthenticationException(error); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authentication/OAuth2PasswordAuthenticationToken.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authentication; 2 | 3 | import java.util.Map; 4 | import java.util.Set; 5 | import org.springframework.security.oauth2.core.AuthorizationGrantType; 6 | 7 | /** 8 | * @author guqing 9 | * @since 2.0.0 10 | */ 11 | public class OAuth2PasswordAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken { 12 | private final String username; 13 | 14 | private final String password; 15 | 16 | private final Set scopes; 17 | 18 | public OAuth2PasswordAuthenticationToken(String username, String password, 19 | Set scopes, Map additionalParameters) { 20 | super(AuthorizationGrantType.PASSWORD, additionalParameters); 21 | this.username = username; 22 | this.password = password; 23 | this.scopes = scopes; 24 | } 25 | 26 | public String getUsername() { 27 | return this.username; 28 | } 29 | 30 | public String getPassword() { 31 | return this.password; 32 | } 33 | 34 | public Set getScopes() { 35 | return scopes; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authentication/OAuth2RefreshTokenAuthenticationToken.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authentication; 2 | 3 | import java.util.Collections; 4 | import java.util.HashSet; 5 | import java.util.Map; 6 | import java.util.Set; 7 | import org.springframework.lang.Nullable; 8 | import org.springframework.security.oauth2.core.AuthorizationGrantType; 9 | import org.springframework.util.Assert; 10 | 11 | /** 12 | * @author guqing 13 | * @since 2.0.0 14 | */ 15 | public class OAuth2RefreshTokenAuthenticationToken 16 | extends OAuth2AuthorizationGrantAuthenticationToken { 17 | private final String refreshToken; 18 | private final Set scopes; 19 | 20 | /** 21 | * Constructs an {@code OAuth2RefreshTokenAuthenticationToken} using the provided parameters. 22 | * 23 | * @param refreshToken the refresh token 24 | * @param scopes the requested scope(s) 25 | * @param additionalParameters the additional parameters 26 | */ 27 | public OAuth2RefreshTokenAuthenticationToken(String refreshToken, 28 | @Nullable Set scopes, @Nullable Map additionalParameters) { 29 | super(AuthorizationGrantType.REFRESH_TOKEN, additionalParameters); 30 | Assert.hasText(refreshToken, "refreshToken cannot be empty"); 31 | this.refreshToken = refreshToken; 32 | this.scopes = Collections.unmodifiableSet( 33 | scopes != null ? new HashSet<>(scopes) : Collections.emptySet()); 34 | } 35 | 36 | /** 37 | * Returns the refresh token. 38 | * 39 | * @return the refresh token 40 | */ 41 | public String getRefreshToken() { 42 | return this.refreshToken; 43 | } 44 | 45 | /** 46 | * Returns the requested scope(s). 47 | * 48 | * @return the requested scope(s), or an empty {@code Set} if not available 49 | */ 50 | public Set getScopes() { 51 | return this.scopes; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authentication/OAuth2TokenGenerator.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authentication; 2 | 3 | import org.springframework.lang.Nullable; 4 | import org.springframework.security.oauth2.core.ClaimAccessor; 5 | import org.springframework.security.oauth2.core.OAuth2Token; 6 | 7 | /** 8 | * Implementations of this interface are responsible for generating an {@link OAuth2Token} 9 | * using the attributes contained in the {@link OAuth2TokenContext}. 10 | * 11 | * @param the type of the OAuth 2.0 Token 12 | * @author guqing 13 | * @since 2.0.0 14 | * @see OAuth2Token 15 | * @see OAuth2TokenContext 16 | * @see ClaimAccessor 17 | */ 18 | @FunctionalInterface 19 | public interface OAuth2TokenGenerator { 20 | /** 21 | * Generate an OAuth 2.0 Token using the attributes contained in the {@link OAuth2TokenContext}, 22 | * or return {@code null} if the {@link OAuth2TokenContext#getTokenType()} is not supported. 23 | * 24 | *

25 | * If the returned {@link OAuth2Token} has a set of claims, it should implement 26 | * {@link ClaimAccessor} 27 | * in order for it to be stored with the {@link OAuth2Authorization}. 28 | * 29 | * @param context the context containing the OAuth 2.0 Token attributes 30 | * @return an {@link OAuth2Token} or {@code null} if the 31 | * {@link OAuth2TokenContext#getTokenType()} is not supported 32 | */ 33 | @Nullable 34 | T generate(OAuth2TokenContext context); 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authentication/OAuth2TokenType.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authentication; 2 | 3 | import java.io.Serializable; 4 | import org.springframework.util.Assert; 5 | 6 | /** 7 | * @author guqing 8 | * @since 2.0.0 9 | */ 10 | public record OAuth2TokenType(String value) implements Serializable { 11 | public static final OAuth2TokenType ACCESS_TOKEN = new OAuth2TokenType("access_token"); 12 | public static final OAuth2TokenType REFRESH_TOKEN = new OAuth2TokenType("refresh_token"); 13 | 14 | /** 15 | * Constructs an {@code OAuth2TokenType} using the provided value. 16 | * 17 | * @param value the value of the token type 18 | */ 19 | public OAuth2TokenType { 20 | Assert.hasText(value, "value cannot be empty"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authentication/ProviderContext.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authentication; 2 | 3 | import java.util.function.Supplier; 4 | import org.springframework.lang.Nullable; 5 | import org.springframework.util.Assert; 6 | 7 | /** 8 | * A context that holds information of the Provider. 9 | * 10 | * @author guqing 11 | * @since 2.0.0 12 | */ 13 | public record ProviderContext(ProviderSettings providerSettings, 14 | @Nullable Supplier issuerSupplier) { 15 | /** 16 | * Constructs a {@code ProviderContext} using the provided parameters. 17 | * 18 | * @param providerSettings the provider settings 19 | * @param issuerSupplier a {@code Supplier} for the {@code URL} of the Provider's issuer 20 | * identifier 21 | */ 22 | public ProviderContext { 23 | Assert.notNull(providerSettings, "providerSettings cannot be null"); 24 | } 25 | 26 | /** 27 | * Returns the {@link ProviderSettings}. 28 | * 29 | * @return the {@link ProviderSettings} 30 | */ 31 | @Override 32 | public ProviderSettings providerSettings() { 33 | return this.providerSettings; 34 | } 35 | 36 | /** 37 | * Returns the {@code URL} of the Provider's issuer identifier. 38 | * The issuer identifier is resolved from the constructor parameter {@code Supplier} 39 | * or if not provided then defaults to {@link ProviderSettings#getIssuer()}. 40 | * 41 | * @return the {@code URL} of the Provider's issuer identifier 42 | */ 43 | public String getIssuer() { 44 | return this.issuerSupplier != null 45 | ? this.issuerSupplier.get() : 46 | providerSettings().getIssuer(); 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authentication/ProviderContextHolder.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authentication; 2 | 3 | /** 4 | * A holder of {@link ProviderContext} that associates it with the current thread using a {@code 5 | * ThreadLocal}. 6 | * 7 | * @author guqing 8 | * @see ProviderContext 9 | * @see ProviderContextFilter 10 | * @since 2.0.0 11 | */ 12 | public final class ProviderContextHolder { 13 | private static final ThreadLocal holder = new ThreadLocal<>(); 14 | 15 | private ProviderContextHolder() { 16 | } 17 | 18 | /** 19 | * Returns the {@link ProviderContext} bound to the current thread. 20 | * 21 | * @return the {@link ProviderContext} 22 | */ 23 | public static ProviderContext getProviderContext() { 24 | return holder.get(); 25 | } 26 | 27 | /** 28 | * Bind the given {@link ProviderContext} to the current thread. 29 | * 30 | * @param providerContext the {@link ProviderContext} 31 | */ 32 | public static void setProviderContext(ProviderContext providerContext) { 33 | if (providerContext == null) { 34 | resetProviderContext(); 35 | } else { 36 | holder.set(providerContext); 37 | } 38 | } 39 | 40 | /** 41 | * Reset the {@link ProviderContext} bound to the current thread. 42 | */ 43 | public static void resetProviderContext() { 44 | holder.remove(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authentication/verifier/BearerTokenAuthentication.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authentication.verifier; 2 | 3 | import java.util.Collection; 4 | import java.util.Collections; 5 | import java.util.LinkedHashMap; 6 | import java.util.Map; 7 | import org.springframework.security.core.GrantedAuthority; 8 | import org.springframework.security.core.Transient; 9 | import org.springframework.security.oauth2.core.OAuth2AccessToken; 10 | import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal; 11 | import org.springframework.util.Assert; 12 | 13 | /** 14 | * An {@link org.springframework.security.core.Authentication} token that represents a 15 | * successful authentication as obtained through a bearer token. 16 | * 17 | * @author guqing 18 | * @since 2.0.0 19 | */ 20 | @Transient 21 | public class BearerTokenAuthentication 22 | extends AbstractOAuth2TokenAuthenticationToken { 23 | private final Map attributes; 24 | 25 | /** 26 | * Constructs a {@link BearerTokenAuthentication} with the provided arguments 27 | * 28 | * @param principal The OAuth 2.0 attributes 29 | * @param credentials The verified token 30 | * @param authorities The authorities associated with the given token 31 | */ 32 | public BearerTokenAuthentication(OAuth2AuthenticatedPrincipal principal, 33 | OAuth2AccessToken credentials, 34 | Collection authorities) { 35 | super(credentials, principal, credentials, authorities); 36 | Assert.isTrue(credentials.getTokenType() == OAuth2AccessToken.TokenType.BEARER, 37 | "credentials must be a bearer token"); 38 | this.attributes = 39 | Collections.unmodifiableMap(new LinkedHashMap<>(principal.getAttributes())); 40 | setAuthenticated(true); 41 | } 42 | 43 | @Override 44 | public Map getTokenAttributes() { 45 | return this.attributes; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authentication/verifier/BearerTokenAuthenticationToken.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authentication.verifier; 2 | 3 | import java.util.Collections; 4 | import org.springframework.security.authentication.AbstractAuthenticationToken; 5 | import org.springframework.security.core.Authentication; 6 | import org.springframework.util.Assert; 7 | 8 | /** 9 | * An {@link Authentication} that contains a 10 | * Bearer Token. 11 | * 12 | * @author guqing 13 | * @since 2.0.0 14 | */ 15 | public class BearerTokenAuthenticationToken extends AbstractAuthenticationToken { 16 | private final String token; 17 | 18 | /** 19 | * Create a {@code BearerTokenAuthenticationToken} using the provided parameter(s) 20 | * 21 | * @param token - the bearer token 22 | */ 23 | public BearerTokenAuthenticationToken(String token) { 24 | super(Collections.emptyList()); 25 | Assert.hasText(token, "token cannot be empty"); 26 | this.token = token; 27 | } 28 | 29 | /** 30 | * Get the 31 | * Bearer Token 32 | * 33 | * @return the token that proves the caller's authority to perform the 34 | * {@link jakarta.servlet.http.HttpServletRequest} 35 | */ 36 | public String getToken() { 37 | return this.token; 38 | } 39 | 40 | @Override 41 | public Object getCredentials() { 42 | return this.getToken(); 43 | } 44 | 45 | @Override 46 | public Object getPrincipal() { 47 | return this.getToken(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authentication/verifier/BearerTokenErrorCodes.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authentication.verifier; 2 | 3 | /** 4 | * Standard error codes defined by the OAuth 2.0 Authorization Framework: Bearer Token 5 | * Usage. 6 | * 7 | * @author guqing 8 | * @see 9 | * RFC 6750 Section 3.1: Error Codes 10 | * @since 2.0.0 11 | */ 12 | public interface BearerTokenErrorCodes { 13 | /** 14 | * {@code invalid_request} - The request is missing a required parameter, includes an 15 | * unsupported parameter or parameter value, repeats the same parameter, uses more 16 | * than one method for including an access token, or is otherwise malformed. 17 | */ 18 | String INVALID_REQUEST = "invalid_request"; 19 | 20 | /** 21 | * {@code invalid_token} - The access token provided is expired, revoked, malformed, 22 | * or invalid for other reasons. 23 | */ 24 | String INVALID_TOKEN = "invalid_token"; 25 | 26 | /** 27 | * {@code insufficient_scope} - The request requires higher privileges than provided 28 | * by the access token. 29 | */ 30 | String INSUFFICIENT_SCOPE = "insufficient_scope"; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authentication/verifier/BearerTokenResolver.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authentication.verifier; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import org.springframework.security.oauth2.core.OAuth2AuthenticationException; 5 | 6 | /** 7 | * A strategy for resolving 8 | * Bearer Token 9 | * s from the {@link HttpServletRequest}. 10 | * 11 | * @author guqing 12 | * @see 13 | * RFC 6750 Section 2: Authenticated Requests 14 | * @since 2.0.0 15 | */ 16 | @FunctionalInterface 17 | public interface BearerTokenResolver { 18 | /** 19 | * Resolve any 20 | * Bearer Token 21 | * value from the request. 22 | * 23 | * @param request the request 24 | * @return the Bearer Token value or {@code null} if none found 25 | * @throws OAuth2AuthenticationException if the found token is invalid 26 | */ 27 | String resolve(HttpServletRequest request); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authentication/verifier/InvalidBearerTokenException.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authentication.verifier; 2 | 3 | import org.springframework.security.oauth2.core.OAuth2AuthenticationException; 4 | 5 | /** 6 | * An {@link OAuth2AuthenticationException} that indicates an invalid bearer token. 7 | * 8 | * @author guqing 9 | * @since 2.0.0 10 | */ 11 | public class InvalidBearerTokenException extends OAuth2AuthenticationException { 12 | /** 13 | * Construct an instance of {@link InvalidBearerTokenException} given the provided 14 | * description. 15 | *

16 | * The description will be wrapped into an 17 | * {@link org.springframework.security.oauth2.core.OAuth2Error} instance as the 18 | * {@code error_description}. 19 | * 20 | * @param description the description 21 | */ 22 | public InvalidBearerTokenException(String description) { 23 | super(BearerTokenErrors.invalidToken(description)); 24 | } 25 | 26 | /** 27 | * Construct an instance of {@link InvalidBearerTokenException} given the provided 28 | * description and cause 29 | *

30 | * The description will be wrapped into an 31 | * {@link org.springframework.security.oauth2.core.OAuth2Error} instance as the 32 | * {@code error_description}. 33 | * 34 | * @param description the description 35 | * @param cause the causing exception 36 | */ 37 | public InvalidBearerTokenException(String description, Throwable cause) { 38 | super(BearerTokenErrors.invalidToken(description), cause); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authentication/verifier/JwtProvidedDecoderAuthenticationManagerResolver.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authentication.verifier; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import org.springframework.security.authentication.AuthenticationManager; 5 | import org.springframework.security.authentication.AuthenticationManagerResolver; 6 | import org.springframework.security.oauth2.jwt.JwtDecoder; 7 | import org.springframework.util.Assert; 8 | 9 | /** 10 | * A jwt resolver for {@link AuthenticationManager} use {@link JwtDecoder}. 11 | * 12 | * @author guqing 13 | * @since 2.0.0 14 | */ 15 | public record JwtProvidedDecoderAuthenticationManagerResolver(JwtDecoder jwtDecoder) 16 | implements AuthenticationManagerResolver { 17 | public JwtProvidedDecoderAuthenticationManagerResolver { 18 | Assert.notNull(jwtDecoder, "jwtDecoder cannot be null"); 19 | } 20 | 21 | @Override 22 | public AuthenticationManager resolve(HttpServletRequest request) { 23 | return new JwtAuthenticationProvider(jwtDecoder)::authenticate; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authorization/AttributesRecord.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authorization; 2 | 3 | import org.springframework.security.core.userdetails.UserDetails; 4 | 5 | /** 6 | * @author guqing 7 | * @since 2.0.0 8 | */ 9 | public class AttributesRecord implements Attributes { 10 | private final RequestInfo requestInfo; 11 | private final UserDetails user; 12 | 13 | public AttributesRecord(UserDetails user, RequestInfo requestInfo) { 14 | this.requestInfo = requestInfo; 15 | this.user = user; 16 | } 17 | 18 | @Override 19 | public UserDetails getUser() { 20 | return this.user; 21 | } 22 | 23 | @Override 24 | public String getVerb() { 25 | return requestInfo.getVerb(); 26 | } 27 | 28 | @Override 29 | public boolean isReadOnly() { 30 | String verb = requestInfo.getVerb(); 31 | return "get".equals(verb) 32 | || "list".equals(verb) 33 | || "watch".equals(verb); 34 | } 35 | 36 | @Override 37 | public String getResource() { 38 | return requestInfo.getResource(); 39 | } 40 | 41 | @Override 42 | public String getSubresource() { 43 | return requestInfo.getSubresource(); 44 | } 45 | 46 | @Override 47 | public String getName() { 48 | return requestInfo.getName(); 49 | } 50 | 51 | @Override 52 | public String getApiGroup() { 53 | return requestInfo.getApiGroup(); 54 | } 55 | 56 | @Override 57 | public String getApiVersion() { 58 | return requestInfo.getApiVersion(); 59 | } 60 | 61 | @Override 62 | public boolean isResourceRequest() { 63 | return requestInfo.isResourceRequest(); 64 | } 65 | 66 | @Override 67 | public String getPath() { 68 | return requestInfo.getPath(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authorization/AuthorizationRuleResolver.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authorization; 2 | 3 | import org.springframework.security.core.userdetails.UserDetails; 4 | 5 | /** 6 | * @author guqing 7 | * @since 2.0.0 8 | */ 9 | public interface AuthorizationRuleResolver { 10 | 11 | /** 12 | * rulesFor returns the list of rules that apply to a given user. 13 | * If an error is returned, the slice of PolicyRules may not be complete, 14 | * but it contains all retrievable rules. 15 | * This is done because policy rules are purely additive and policy determinations 16 | * can be made on the basis of those rules that are found. 17 | * 18 | * @param user authenticated user info 19 | */ 20 | PolicyRuleList rulesFor(UserDetails user); 21 | 22 | /** 23 | * visitRulesFor invokes visitor() with each rule that applies to a given user 24 | * and each error encountered resolving those rules. Rule may be null if err is non-nil. 25 | * If visitor() returns false, visiting is short-circuited. 26 | * 27 | * @param user user info 28 | * @param visitor visitor 29 | */ 30 | void visitRulesFor(UserDetails user, RuleAccumulator visitor); 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authorization/AuthorizingVisitor.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authorization; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * authorizing visitor short-circuits once allowed, and collects any resolution errors encountered. 8 | * 9 | * @author guqing 10 | * @since 2.0.0 11 | */ 12 | class AuthorizingVisitor implements RuleAccumulator { 13 | private final RbacRequestEvaluation requestEvaluation = new RbacRequestEvaluation(); 14 | 15 | private final Attributes requestAttributes; 16 | 17 | private boolean allowed; 18 | 19 | private String reason; 20 | 21 | private final List errors = new ArrayList<>(4); 22 | 23 | public AuthorizingVisitor(Attributes requestAttributes) { 24 | this.requestAttributes = requestAttributes; 25 | } 26 | 27 | @Override 28 | public boolean visit(String source, PolicyRule rule, Throwable error) { 29 | if (rule != null && requestEvaluation.ruleAllows(requestAttributes, rule)) { 30 | this.allowed = true; 31 | this.reason = String.format("RBAC: allowed by %s", source); 32 | return false; 33 | } 34 | if (error != null) { 35 | this.errors.add(error); 36 | } 37 | return true; 38 | } 39 | 40 | public boolean isAllowed() { 41 | return allowed; 42 | } 43 | 44 | public String getReason() { 45 | return reason; 46 | } 47 | 48 | public List getErrors() { 49 | return errors; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authorization/DefaultRoleGetter.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authorization; 2 | 3 | import org.springframework.lang.NonNull; 4 | import org.springframework.stereotype.Component; 5 | import xyz.guqing.creek.extension.ExtensionClient; 6 | 7 | /** 8 | * @author guqing 9 | * @since 2.0.0 10 | */ 11 | @Component 12 | public class DefaultRoleGetter implements RoleGetter { 13 | 14 | private final ExtensionClient extensionClient; 15 | 16 | public DefaultRoleGetter(ExtensionClient extensionClient) { 17 | this.extensionClient = extensionClient; 18 | } 19 | 20 | @Override 21 | @NonNull 22 | public Role getRole(@NonNull String name) { 23 | return extensionClient.fetch(Role.class, name).orElseThrow(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authorization/PolicyRuleList.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authorization; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | 7 | /** 8 | * @author guqing 9 | * @since 2.0.0 10 | */ 11 | public class PolicyRuleList extends LinkedList { 12 | private final List errors = new ArrayList<>(4); 13 | 14 | /** 15 | * @return true if an error occurred when parsing PolicyRules 16 | */ 17 | public boolean hasErrors() { 18 | return !errors.isEmpty(); 19 | } 20 | 21 | public List getErrors() { 22 | return errors; 23 | } 24 | 25 | public PolicyRuleList addError(Throwable error) { 26 | errors.add(error); 27 | return this; 28 | } 29 | 30 | public PolicyRuleList addErrors(List errors) { 31 | this.errors.addAll(errors); 32 | return this; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authorization/RequestInfo.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authorization; 2 | 3 | import java.util.Objects; 4 | import lombok.Getter; 5 | import lombok.ToString; 6 | import org.apache.commons.lang3.StringUtils; 7 | 8 | /** 9 | * @author guqing 10 | * @since 2.0.0 11 | */ 12 | @Getter 13 | @ToString 14 | public class RequestInfo { 15 | boolean isResourceRequest; 16 | final String path; 17 | String namespace; 18 | String verb; 19 | String apiPrefix; 20 | String apiGroup; 21 | String apiVersion; 22 | String resource; 23 | String subresource; 24 | String name; 25 | String[] parts; 26 | 27 | public RequestInfo(boolean isResourceRequest, String path, String verb) { 28 | this(isResourceRequest, path, null, verb, null, null, null, null, null, null, null); 29 | } 30 | 31 | public RequestInfo(boolean isResourceRequest, String path, String namespace, String verb, 32 | String apiPrefix, 33 | String apiGroup, 34 | String apiVersion, String resource, String subresource, String name, 35 | String[] parts) { 36 | this.isResourceRequest = isResourceRequest; 37 | this.path = StringUtils.defaultString(path, ""); 38 | this.namespace = StringUtils.defaultString(namespace, ""); 39 | this.verb = StringUtils.defaultString(verb, ""); 40 | this.apiPrefix = StringUtils.defaultString(apiPrefix, ""); 41 | this.apiGroup = StringUtils.defaultString(apiGroup, ""); 42 | this.apiVersion = StringUtils.defaultString(apiVersion, ""); 43 | this.resource = StringUtils.defaultString(resource, ""); 44 | this.subresource = StringUtils.defaultString(subresource, ""); 45 | this.name = StringUtils.defaultString(name, ""); 46 | this.parts = Objects.requireNonNullElseGet(parts, () -> new String[] {}); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authorization/ResourceRuleInfo.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authorization; 2 | 3 | /** 4 | * @author guqing 5 | * @since 2.0.0 6 | */ 7 | public class ResourceRuleInfo { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authorization/Role.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authorization; 2 | 3 | import io.swagger.v3.oas.annotations.media.Schema; 4 | import java.util.List; 5 | import lombok.Data; 6 | import lombok.EqualsAndHashCode; 7 | import lombok.ToString; 8 | import xyz.guqing.creek.extension.AbstractExtension; 9 | import xyz.guqing.creek.extension.GVK; 10 | 11 | /** 12 | * @author guqing 13 | * @since 2.0.0 14 | */ 15 | @Data 16 | @EqualsAndHashCode(callSuper = true) 17 | @ToString(callSuper = true) 18 | @GVK(group = "", version = "v1alpha1", kind = "Role", plural = "roles", singular = "role") 19 | public class Role extends AbstractExtension { 20 | 21 | @Schema(minLength = 1) 22 | List rules; 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authorization/RoleBinding.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authorization; 2 | 3 | import java.util.List; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import lombok.ToString; 7 | import xyz.guqing.creek.extension.AbstractExtension; 8 | import xyz.guqing.creek.extension.GVK; 9 | 10 | /** 11 | * RoleBinding references a role, but does not contain it. 12 | * It can reference a Role in the global. 13 | * It adds who information via Subjects. 14 | * 15 | * @author guqing 16 | * @since 2.0.0 17 | */ 18 | @Data 19 | @EqualsAndHashCode(callSuper = true) 20 | @ToString(callSuper = true) 21 | @GVK(group = "", version = "v1alpha1", kind = "RoleBinding", plural = "rolebindings", 22 | singular = "rolebinding") 23 | public class RoleBinding extends AbstractExtension { 24 | 25 | /** 26 | * Subjects holds references to the objects the role applies to. 27 | */ 28 | List subjects; 29 | 30 | /** 31 | * RoleRef can reference a Role in the current namespace or a ClusterRole in the global 32 | * namespace. 33 | * If the RoleRef cannot be resolved, the Authorizer must return an error. 34 | */ 35 | RoleRef roleRef; 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authorization/RoleBindingLister.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authorization; 2 | 3 | import java.util.Set; 4 | 5 | /** 6 | * @author guqing 7 | * @since 2.0.0 8 | */ 9 | @FunctionalInterface 10 | public interface RoleBindingLister { 11 | 12 | Set listBoundRoleNames(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authorization/RoleGetter.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authorization; 2 | 3 | import org.springframework.lang.NonNull; 4 | 5 | /** 6 | * @author guqing 7 | * @since 2.0.0 8 | */ 9 | public interface RoleGetter { 10 | 11 | @NonNull 12 | Role getRole(String name); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authorization/RoleRef.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authorization; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * RoleRef contains information that points to the role being used. 7 | * 8 | * @author guqing 9 | * @since 2.0.0 10 | */ 11 | @Data 12 | public class RoleRef { 13 | 14 | /** 15 | * Kind is the type of resource being referenced. 16 | */ 17 | String kind; 18 | 19 | /** 20 | * Name is the name of resource being referenced. 21 | */ 22 | String name; 23 | 24 | /** 25 | * APIGroup is the group for the resource being referenced. 26 | */ 27 | String apiGroup; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authorization/RuleAccumulator.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authorization; 2 | 3 | /** 4 | * @author guqing 5 | * @since 2.0.0 6 | */ 7 | public interface RuleAccumulator { 8 | boolean visit(String source, PolicyRule rule, Throwable err); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/authorization/Subject.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authorization; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @author guqing 7 | * @since 2.0.0 8 | */ 9 | @Data 10 | public class Subject { 11 | /** 12 | * Kind of object being referenced. Values defined by this API group are "User", "Group", 13 | * and "ServiceAccount". 14 | * If the Authorizer does not recognized the kind value, the Authorizer should report 15 | * an error. 16 | */ 17 | String kind; 18 | 19 | /** 20 | * Name of the object being referenced. 21 | */ 22 | String name; 23 | 24 | /** 25 | * APIGroup holds the API group of the referenced subject. 26 | * Defaults to "" for ServiceAccount subjects. 27 | * Defaults to "rbac.authorization.k8s.io" for User and Group subjects. 28 | */ 29 | String apiGroup; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/identity/entrypoint/Oauth2LogoutHandler.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.entrypoint; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import jakarta.servlet.http.HttpServletResponse; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.security.core.Authentication; 7 | import org.springframework.security.web.authentication.logout.LogoutHandler; 8 | import xyz.guqing.creek.identity.authentication.OAuth2AuthorizationService; 9 | import xyz.guqing.creek.identity.authentication.OAuth2TokenType; 10 | import xyz.guqing.creek.identity.authentication.verifier.JwtAuthenticationToken; 11 | 12 | /** 13 | *

Performs a logout by {@link OAuth2AuthorizationService}.

14 | *

Will remove the {@link Authentication} from the {@link OAuth2AuthorizationService} if the 15 | * specific instance of {@link Authentication} is {@link JwtAuthenticationToken}.

16 | * 17 | * @author guqing 18 | * @see OAuth2AuthorizationService 19 | * @see Authentication 20 | * @see JwtAuthenticationToken 21 | * @since 2.0.0 22 | */ 23 | @Slf4j 24 | public class Oauth2LogoutHandler implements LogoutHandler { 25 | 26 | private final OAuth2AuthorizationService oauth2AuthorizationService; 27 | 28 | public Oauth2LogoutHandler(OAuth2AuthorizationService oauth2AuthorizationService) { 29 | this.oauth2AuthorizationService = oauth2AuthorizationService; 30 | } 31 | 32 | @Override 33 | public void logout(HttpServletRequest request, HttpServletResponse response, 34 | Authentication authentication) { 35 | log.debug("Logging out [{}]", authentication); 36 | if (authentication instanceof JwtAuthenticationToken jwtAuthenticationToken) { 37 | String tokenValue = jwtAuthenticationToken.getToken().getTokenValue(); 38 | var oauth2Authorization = oauth2AuthorizationService.findByToken( 39 | tokenValue, OAuth2TokenType.ACCESS_TOKEN); 40 | oauth2AuthorizationService.remove(oauth2Authorization); 41 | log.debug("Removed oauth2Authorization [{}]", oauth2Authorization); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/infra/config/WebMvcConfig.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.infra.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.web.bind.annotation.RestController; 5 | import org.springframework.web.method.HandlerTypePredicate; 6 | import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; 7 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 8 | import xyz.guqing.creek.AppApplication; 9 | 10 | /** 11 | * Spring web mvc config. 12 | * 13 | * @author guqing 14 | * @date 2022-04-12 15 | */ 16 | @Configuration 17 | public class WebMvcConfig implements WebMvcConfigurer { 18 | 19 | @Override 20 | public void configurePathMatch(PathMatchConfigurer configurer) { 21 | configurer.addPathPrefix("/api/v1", 22 | c -> HandlerTypePredicate.forAnnotation(RestController.class) 23 | .and(HandlerTypePredicate.forBasePackage(AppApplication.class.getPackageName())) 24 | .test(c) 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/infra/properties/CreekProperties.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.infra.properties; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | /** 6 | * @author guqing 7 | * @date 2022-04-12 8 | */ 9 | @ConfigurationProperties(prefix = "creek") 10 | public class CreekProperties { 11 | 12 | private final JwtProperties jwt = new JwtProperties(); 13 | 14 | public JwtProperties getJwt() { 15 | return jwt; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/infra/utils/Base62Utils.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.infra.utils; 2 | 3 | import io.seruco.encoding.base62.Base62; 4 | import java.nio.charset.Charset; 5 | import java.nio.charset.StandardCharsets; 6 | import org.apache.commons.lang3.StringUtils; 7 | 8 | /** 9 | *

Base62 tool class, which provides the encoding and decoding scheme of base62.

10 | * 11 | * @author guqing 12 | * @since 2.0.0 13 | */ 14 | public class Base62Utils { 15 | private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; 16 | private static final Base62 INSTANCE = Base62.createInstance(); 17 | 18 | public static String encode(String source) { 19 | return encode(source, DEFAULT_CHARSET); 20 | } 21 | 22 | /** 23 | * Base62 encode. 24 | * 25 | * @param source the encoded base62 string 26 | * @param charset the charset default is utf_8 27 | * @return encoded string by base62 28 | */ 29 | public static String encode(String source, Charset charset) { 30 | return encode(StringUtils.getBytes(source, charset)); 31 | } 32 | 33 | public static String encode(byte[] source) { 34 | return new String(INSTANCE.encode(source)); 35 | } 36 | 37 | /** 38 | * Base62 decode. 39 | * 40 | * @param base62Str the Base62 decoded string 41 | * @return decoded bytes 42 | */ 43 | public static byte[] decode(String base62Str) { 44 | return decode(StringUtils.getBytes(base62Str, DEFAULT_CHARSET)); 45 | } 46 | 47 | public static byte[] decode(byte[] base62bytes) { 48 | return INSTANCE.decode(base62bytes); 49 | } 50 | 51 | public static String decodeToString(String source) { 52 | return decodeToString(source, DEFAULT_CHARSET); 53 | } 54 | 55 | public static String decodeToString(String source, Charset charset) { 56 | return StringUtils.toEncodedString(decode(source), charset); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/infra/utils/YamlUnstructuredLoader.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.infra.utils; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import org.springframework.beans.factory.config.YamlProcessor; 6 | import org.springframework.core.io.Resource; 7 | import xyz.guqing.creek.extension.Unstructured; 8 | 9 | /** 10 | *

Process the content in yaml that matches the {@link DocumentMatcher} and convert it to an 11 | * unstructured list.

12 | *

Multiple resources can be processed at one time.

13 | *

The following specified key must be included before the resource can be processed: 14 | *

15 |  *     apiVersion
16 |  *     kind
17 |  *     metadata.name
18 |  * 
19 | * Otherwise, skip it and continue to read the next resource. 20 | *

21 | * 22 | * @author guqing 23 | * @since 2.0.0 24 | */ 25 | public class YamlUnstructuredLoader extends YamlProcessor { 26 | 27 | private static final DocumentMatcher DEFAULT_UNSTRUCTURED_MATCHER = properties -> { 28 | if (properties.containsKey("apiVersion") 29 | && properties.containsKey("kind") 30 | && properties.containsKey("metadata.name")) { 31 | return MatchStatus.FOUND; 32 | } 33 | return MatchStatus.NOT_FOUND; 34 | }; 35 | 36 | public YamlUnstructuredLoader(Resource... resources) { 37 | setResources(resources); 38 | setDocumentMatchers(DEFAULT_UNSTRUCTURED_MATCHER); 39 | } 40 | 41 | public List load() { 42 | List unstructuredList = new ArrayList<>(); 43 | process((properties, map) -> { 44 | Unstructured unstructured = JsonUtils.mapToObject(map, Unstructured.class); 45 | unstructuredList.add(unstructured); 46 | }); 47 | return unstructuredList; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/mapper/ActionLogMapper.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import xyz.guqing.creek.model.entity.ActionLog; 5 | 6 | /** 7 | * 系统操作日志表mapper接口 8 | * @author guqing 9 | * @date 2020-06-01 10 | */ 11 | public interface ActionLogMapper extends BaseMapper { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/mapper/ApiResourceMapper.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import xyz.guqing.creek.model.entity.ApiResource; 5 | 6 | /** 7 | * @author guqing 8 | * @since 2022-01-12 9 | */ 10 | public interface ApiResourceMapper extends BaseMapper { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/mapper/ApiScopeMapper.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import xyz.guqing.creek.model.entity.ApiScope; 5 | 6 | /** 7 | * @author guqing 8 | * @since 2022-01-12 9 | */ 10 | public interface ApiScopeMapper extends BaseMapper { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/mapper/CredentialsMapper.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import xyz.guqing.creek.model.entity.Credentials; 5 | 6 | /** 7 | * @author guqing 8 | * @since 2022-01-15 9 | */ 10 | public interface CredentialsMapper extends BaseMapper { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/mapper/MenuMapper.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import xyz.guqing.creek.model.entity.Menu; 5 | 6 | /** 7 | *

8 | * 菜单表 Mapper 接口 9 | *

10 | * 11 | * @author guqing 12 | * @since 2020-05-21 13 | */ 14 | public interface MenuMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/mapper/OauthAccessTokenMapper.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import java.util.List; 5 | import org.apache.ibatis.annotations.Select; 6 | import xyz.guqing.creek.model.entity.OauthAccessToken; 7 | 8 | public interface OauthAccessTokenMapper extends BaseMapper { 9 | 10 | @Select("select token_id, token from oauth_access_token where authentication_id = #{authenticationId}") 11 | OauthAccessToken selectFromAuthentication(String authenticationId); 12 | 13 | @Select("select token_id, token from oauth_access_token where user_name = #{username}") 14 | List selectByUsername(String username); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/mapper/OauthRefreshTokenMapper.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import xyz.guqing.creek.model.entity.OauthRefreshToken; 5 | 6 | public interface OauthRefreshTokenMapper extends BaseMapper { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/mapper/RoleMapper.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import xyz.guqing.creek.model.entity.Role; 5 | 6 | /** 7 | * @author guqing 8 | * @date 2020-06-03 9 | */ 10 | public interface RoleMapper extends BaseMapper { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/mapper/RoleResourceMapper.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import java.util.List; 5 | import xyz.guqing.creek.model.entity.RoleResource; 6 | 7 | /** 8 | * @author guqing 9 | * @date 2020-06-09 10 | */ 11 | public interface RoleResourceMapper extends BaseMapper { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/mapper/UserConnectionMapper.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import xyz.guqing.creek.model.entity.UserConnection; 5 | 6 | /** 7 | *

8 | * 系统用户社交账户关联表 Mapper 接口 9 | *

10 | * 11 | * @author guqing 12 | * @since 2020-05-21 13 | */ 14 | public interface UserConnectionMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/mapper/UserGroupMapper.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import xyz.guqing.creek.model.entity.UserGroup; 5 | 6 | /** 7 | * 用户组表mapper接口 8 | * @author guqing 9 | * @date 2020-06-05 10 | */ 11 | public interface UserGroupMapper extends BaseMapper { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/mapper/UserLoginLogMapper.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import xyz.guqing.creek.model.entity.UserLoginLog; 5 | 6 | /** 7 | *

8 | * 登录日志表 Mapper 接口 9 | *

10 | * 11 | * @author guqing 12 | * @since 2020-05-21 13 | */ 14 | public interface UserLoginLogMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/mapper/UserMapper.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 5 | import org.apache.ibatis.annotations.Param; 6 | import xyz.guqing.creek.model.bo.CurrentUser; 7 | import xyz.guqing.creek.model.dos.UserDO; 8 | import xyz.guqing.creek.model.entity.User; 9 | import xyz.guqing.creek.model.params.UserQuery; 10 | 11 | import java.util.Optional; 12 | 13 | /** 14 | *

15 | * 用户表 Mapper 接口 16 | *

17 | * 18 | * @author guqing 19 | * @since 2020-05-21 20 | */ 21 | public interface UserMapper extends BaseMapper { 22 | /** 23 | * 根据用户名查询用户信息 24 | * @param username 用户名 25 | * @return 返回用户信息的Optional对象 26 | */ 27 | Optional findByUsername(String username); 28 | /** 29 | * 根据条件查询用户信息 30 | * @param userQuery 查询条件 31 | * @param page 分页,必须放在第一位自动分页 32 | * @return 返回查询结果,查询不到数据返回{@code null} 33 | */ 34 | Page findUserBy(Page page, @Param("userQuery") UserQuery userQuery); 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/annotation/ControllerEndpoint.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * @author guqing 10 | * @date 2020-6-1 11 | */ 12 | @Target(ElementType.METHOD) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface ControllerEndpoint { 15 | 16 | String operation() default ""; 17 | 18 | String exceptionMessage() default "系统内部异常"; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/bo/CurrentUser.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.bo; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import com.fasterxml.jackson.annotation.JsonIgnore; 5 | import java.io.Serializable; 6 | import java.util.List; 7 | import lombok.Data; 8 | import lombok.EqualsAndHashCode; 9 | import lombok.experimental.Accessors; 10 | import xyz.guqing.creek.model.entity.Role; 11 | import xyz.guqing.creek.model.entity.User; 12 | 13 | /** 14 | * @author guqing 15 | * @date 2020-05-21 16 | */ 17 | @Data 18 | @Accessors(chain = true) 19 | @EqualsAndHashCode(callSuper = true) 20 | public class CurrentUser extends User implements Serializable { 21 | 22 | private List roles; 23 | 24 | @JsonIgnore 25 | @JSONField(serialize = false) 26 | public String getPassword() { 27 | return super.getPassword(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/bo/MyUserDetails.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.bo; 2 | 3 | import java.time.LocalDateTime; 4 | import java.util.Collection; 5 | import lombok.Data; 6 | import lombok.EqualsAndHashCode; 7 | import org.springframework.security.core.GrantedAuthority; 8 | import org.springframework.security.core.userdetails.User; 9 | 10 | /** 11 | * @author guqing 12 | * @date 2020-5-13 13 | */ 14 | @Data 15 | @SuppressWarnings("all") 16 | @EqualsAndHashCode(callSuper = true) 17 | public class MyUserDetails extends User { 18 | 19 | private Long id; 20 | 21 | /** 22 | * 最近访问时间 23 | */ 24 | private LocalDateTime lastLoginTime; 25 | 26 | public MyUserDetails(String username, String password, 27 | Collection authorities) { 28 | super(username, password, authorities); 29 | } 30 | 31 | public MyUserDetails(String username, String password, boolean enabled, 32 | boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, 33 | Collection authorities) { 34 | super(username, password, enabled, accountNonExpired, credentialsNonExpired, 35 | accountNonLocked, authorities); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/bo/RouterMeta.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.bo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * Vue路由 Meta 10 | * 11 | * @author MrBird 12 | */ 13 | @Data 14 | @JsonInclude(JsonInclude.Include.NON_NULL) 15 | public class RouterMeta implements Serializable { 16 | 17 | private static final long serialVersionUID = 5499925008927195914L; 18 | 19 | private String title; 20 | private String icon; 21 | private Boolean hidden = false; 22 | private Boolean keepAlive = false; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/bo/VueRouter.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.bo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import com.fasterxml.jackson.annotation.JsonInclude; 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | * 构建 Vue路由 13 | * 14 | * @author guqing 15 | */ 16 | @Data 17 | @JsonInclude(JsonInclude.Include.NON_NULL) 18 | public class VueRouter implements Serializable { 19 | 20 | private static final long serialVersionUID = -3327478146308500708L; 21 | 22 | @JsonIgnore 23 | private String id; 24 | @JsonIgnore 25 | private String parentId; 26 | 27 | private String path; 28 | private String name; 29 | private String component; 30 | private String redirect; 31 | private RouterMeta meta; 32 | private List> children; 33 | 34 | @JsonIgnore 35 | private Boolean hasParent = false; 36 | 37 | @JsonIgnore 38 | private Boolean hasChildren = false; 39 | 40 | public void initChildren() { 41 | this.children = new ArrayList<>(); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/constant/CreekConstant.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.constant; 2 | 3 | /** 4 | * 系统常量类 5 | * 6 | * @author guqing 7 | */ 8 | public interface CreekConstant { 9 | 10 | /** 11 | * 排序规则:降序 12 | */ 13 | String ORDER_DESC = "descending"; 14 | /** 15 | * 排序规则:升序 16 | */ 17 | String ORDER_ASC = "ascending"; 18 | 19 | /** 20 | * 验证码 key前缀 21 | */ 22 | String CAPTCHA_PREFIX = "violet:verify:captcha:"; 23 | 24 | /** 25 | * 验证码有效期 26 | */ 27 | Long CAPTCHA_EXPIRE = 300L; 28 | 29 | /** 30 | * 异步线程池名称 31 | */ 32 | String ASYNC_POOL = "creekAsyncThreadPool"; 33 | 34 | /** 35 | * Java默认临时目录 36 | */ 37 | String JAVA_TEMP_DIR = "java.io.tmpdir"; 38 | 39 | /** 40 | * 注册用户角色ID 41 | */ 42 | String REGISTER_ROLE_ID = "1"; 43 | 44 | String DEFAULT_PASSWORD = "123456"; 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/constant/ImageTypeConstant.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.constant; 2 | 3 | /** 4 | * 图片类型常量类 5 | * 6 | * @author guqing 7 | */ 8 | public interface ImageTypeConstant { 9 | 10 | /** 11 | * gif类型 12 | */ 13 | String GIF = "gif"; 14 | /** 15 | * png类型 16 | */ 17 | String PNG = "png"; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/constant/ParamsConstant.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.constant; 2 | 3 | /** 4 | * 请求参数常量 5 | * 6 | * @author MrBird 7 | */ 8 | public interface ParamsConstant { 9 | 10 | /** 11 | * 验证码 key 12 | */ 13 | String VALIDATE_CODE_KEY = "key"; 14 | /** 15 | * 验证码 code 16 | */ 17 | String VALIDATE_CODE_CODE = "code"; 18 | /** 19 | * 认证类型参数 key 20 | */ 21 | String GRANT_TYPE = "grant_type"; 22 | /** 23 | * 登录类型 24 | */ 25 | String LOGIN_TYPE = "login_type"; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/constant/RegexpConstant.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.constant; 2 | 3 | /** 4 | * 正则常量 5 | * 6 | * @author guqing 7 | */ 8 | public interface RegexpConstant { 9 | 10 | /** 11 | * 简单手机号正则(这里只是简单校验是否为 11位,实际规则更复杂) 12 | */ 13 | String MOBILE = "^(?:(?:\\+|00)86)?1[3-9]\\d{9}$"; 14 | String EMAIL = "^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.[a-zA-Z0-9]{2,6}$"; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/constant/StringConstant.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.constant; 2 | 3 | /** 4 | * @author guqing 5 | */ 6 | public interface StringConstant { 7 | String AMPERSAND = "&"; 8 | String AND = "and"; 9 | String AT = "@"; 10 | String ASTERISK = "*"; 11 | String STAR = "*"; 12 | String BACK_SLASH = "\\"; 13 | String COLON = ":"; 14 | String DOUBLE_COLON = "::"; 15 | String COMMA = ","; 16 | String DASH = "-"; 17 | String DOLLAR = "$"; 18 | String DOT = "."; 19 | String UNDER_LINE = "_"; 20 | String DOUBLE_DOT = ".."; 21 | String DOT_CLASS = ".class"; 22 | String DOT_JAVA = ".java"; 23 | String DOT_XML = ".xml"; 24 | String EMPTY = ""; 25 | String EQUALS = "="; 26 | String FALSE = "false"; 27 | String SLASH = "/"; 28 | String HASH = "#"; 29 | String HAT = "^"; 30 | String LEFT_BRACE = "{"; 31 | String LEFT_BRACKET = "("; 32 | String LEFT_CHEV = "<"; 33 | String DOT_NEWLINE = ",\n"; 34 | String NEWLINE = "\n"; 35 | String N = "n"; 36 | String NO = "no"; 37 | String NULL = "null"; 38 | String OFF = "off"; 39 | String ON = "on"; 40 | String PERCENT = "%"; 41 | String PIPE = "|"; 42 | String PLUS = "+"; 43 | String QUESTION_MARK = "?"; 44 | String EXCLAMATION_MARK = "!"; 45 | String QUOTE = "\""; 46 | String RETURN = "\r"; 47 | String TAB = "\t"; 48 | String RIGHT_BRACE = "}"; 49 | String RIGHT_BRACKET = ")"; 50 | String RIGHT_CHEV = ">"; 51 | String SEMICOLON = ";"; 52 | String SINGLE_QUOTE = "'"; 53 | String BACKTICK = "`"; 54 | String SPACE = " "; 55 | String TILDA = "~"; 56 | String LEFT_SQ_BRACKET = "["; 57 | String RIGHT_SQ_BRACKET = "]"; 58 | String TRUE = "true"; 59 | String UNDERSCORE = "_"; 60 | String UTF_8 = "UTF-8"; 61 | String US_ASCII = "US-ASCII"; 62 | String ISO_8859_1 = "ISO-8859-1"; 63 | String Y = "y"; 64 | String YES = "yes"; 65 | String ONE = "1"; 66 | String ZERO = "0"; 67 | String DOLLAR_LEFT_BRACE = "${"; 68 | String HASH_LEFT_BRACE = "#{"; 69 | String CRLF = "\r\n"; 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/dos/UserDO.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.dos; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | import xyz.guqing.creek.model.entity.User; 6 | 7 | /** 8 | * user 数据实体 9 | * @author guqing 10 | * @date 2020-05-31 11 | */ 12 | @Data 13 | @EqualsAndHashCode(callSuper = true) 14 | public class UserDO extends User { 15 | private String groupName; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/dto/ActionLogDTO.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.dto; 2 | 3 | import lombok.Data; 4 | import xyz.guqing.creek.model.entity.ActionLog; 5 | import xyz.guqing.creek.model.support.OutputConverter; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | /** 10 | * @author guqing 11 | * @date 2020-07-11 12 | */ 13 | @Data 14 | public class ActionLogDTO implements OutputConverter { 15 | private Long id; 16 | /** 17 | * 操作用户 18 | */ 19 | private String username; 20 | 21 | /** 22 | * 操作内容 23 | */ 24 | private String operation; 25 | 26 | /** 27 | * 执行时间,单位毫秒 28 | */ 29 | private Long executionTime; 30 | 31 | /** 32 | * 操作方法 33 | */ 34 | private String method; 35 | 36 | /** 37 | * 方法参数 38 | */ 39 | private String params; 40 | 41 | /** 42 | * 操作者IP 43 | */ 44 | private String ip; 45 | 46 | /** 47 | * 操作地点 48 | */ 49 | private String location; 50 | 51 | /** 52 | * 创建时间 53 | */ 54 | private LocalDateTime createTime; 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/dto/ApiResourceDTO.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.dto; 2 | 3 | import java.util.List; 4 | import lombok.Data; 5 | import xyz.guqing.creek.model.entity.ApiResource; 6 | import xyz.guqing.creek.model.support.OutputConverter; 7 | 8 | /** 9 | * @author guqing 10 | * @since 2022-01-12 11 | */ 12 | @Data 13 | public class ApiResourceDTO implements OutputConverter { 14 | 15 | String name; 16 | String displayName; 17 | String description; 18 | List scopes; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/dto/ApiScopeDTO.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.dto; 2 | 3 | import lombok.Data; 4 | import xyz.guqing.creek.model.entity.ApiScope; 5 | import xyz.guqing.creek.model.support.OutputConverter; 6 | 7 | /** 8 | * @author guqing 9 | * @since 2022-01-12 10 | */ 11 | @Data 12 | public class ApiScopeDTO implements OutputConverter { 13 | 14 | private String name; 15 | private String displayName; 16 | private String description; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/dto/CredentialsDTO.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.dto; 2 | 3 | import java.time.LocalDateTime; 4 | import lombok.Data; 5 | import xyz.guqing.creek.model.entity.Credentials; 6 | import xyz.guqing.creek.model.support.OutputConverter; 7 | 8 | /** 9 | * @author guqing 10 | * @since 2022-01-15 11 | */ 12 | @Data 13 | public class CredentialsDTO implements OutputConverter { 14 | 15 | private String remark; 16 | private String scopes; 17 | private LocalDateTime expiredAt; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/dto/MenuDTO.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.dto; 2 | 3 | import lombok.Data; 4 | import xyz.guqing.creek.model.entity.Menu; 5 | import xyz.guqing.creek.model.support.OutputConverter; 6 | 7 | /** 8 | * @author guqing 9 | * @date 2020-07-18 10 | */ 11 | @Data 12 | public class MenuDTO implements OutputConverter { 13 | /** 14 | * 没有id玩不转的 15 | */ 16 | private Long id; 17 | 18 | /** 19 | * 上级菜单ID 20 | */ 21 | private Long parentId; 22 | 23 | /** 24 | * 菜单路由名称,英文 25 | */ 26 | private String name; 27 | 28 | /** 29 | * 菜单/按钮的标题 30 | */ 31 | private String title; 32 | 33 | /** 34 | * 是否显示sidebar 35 | */ 36 | private Boolean hidden; 37 | 38 | private Boolean keepAlive; 39 | 40 | /** 41 | * 对应路由path 42 | */ 43 | private String path; 44 | 45 | /** 46 | * 菜单的重定向路径 47 | */ 48 | private String redirect; 49 | 50 | /** 51 | * 对应路由组件component 52 | */ 53 | private String component; 54 | 55 | /** 56 | * 权限标识 57 | */ 58 | private String perms; 59 | 60 | /** 61 | * 图标 62 | */ 63 | private String icon; 64 | 65 | /** 66 | * 类型 0菜单 1按钮 67 | */ 68 | private String type; 69 | 70 | /** 71 | * 排序 72 | */ 73 | private Long sortIndex; 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/dto/MenuTree.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.dto; 2 | 3 | 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import xyz.guqing.creek.model.entity.Menu; 7 | import xyz.guqing.creek.model.support.Tree; 8 | 9 | /** 10 | * @author guqing 11 | */ 12 | @Data 13 | @EqualsAndHashCode(callSuper = true) 14 | public class MenuTree extends Tree { 15 | private String icon; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/dto/RoleDTO.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.dto; 2 | 3 | import java.time.LocalDateTime; 4 | import java.util.Set; 5 | import lombok.Data; 6 | import xyz.guqing.creek.model.entity.Role; 7 | import xyz.guqing.creek.model.support.OutputConverter; 8 | 9 | /** 10 | * @author guqing 11 | * @date 2020-06-04 12 | */ 13 | @Data 14 | public class RoleDTO implements OutputConverter { 15 | 16 | private Long id; 17 | private String roleName; 18 | private String remark; 19 | private Boolean isInternal; 20 | private Set authorities; 21 | private LocalDateTime createTime; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/dto/SimpleRoleDTO.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.dto; 2 | 3 | import lombok.Data; 4 | import xyz.guqing.creek.model.entity.Role; 5 | import xyz.guqing.creek.model.support.OutputConverter; 6 | 7 | /** 8 | * @author guqing 9 | * @since 2022-01-14 10 | */ 11 | @Data 12 | public class SimpleRoleDTO implements OutputConverter { 13 | 14 | private Long id; 15 | private String roleName; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/dto/SocialLoginDTO.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.dto; 2 | 3 | import lombok.Data; 4 | import me.zhyd.oauth.model.AuthUser; 5 | import xyz.guqing.creek.model.entity.OauthAccessToken; 6 | 7 | /** 8 | * @author guqing 9 | * @date 2020-05-26 10 | */ 11 | @Data 12 | public class SocialLoginDTO { 13 | 14 | private OauthAccessToken accessToken; 15 | private AuthUser authUser; 16 | private Boolean isBind; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/dto/UserDTO.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.dto; 2 | 3 | import java.util.Set; 4 | import lombok.Data; 5 | import xyz.guqing.creek.model.dos.UserDO; 6 | import xyz.guqing.creek.model.entity.Role; 7 | import xyz.guqing.creek.model.support.OutputConverter; 8 | 9 | import java.time.LocalDateTime; 10 | import java.util.List; 11 | 12 | /** 13 | * @author guqing 14 | * @date 2020-05-30 15 | */ 16 | @Data 17 | public class UserDTO implements OutputConverter { 18 | private Long id; 19 | 20 | private String username; 21 | 22 | private String nickname; 23 | 24 | private String email; 25 | 26 | private String mobile; 27 | 28 | private Long groupId; 29 | 30 | private String groupName; 31 | 32 | private Set roles; 33 | 34 | private String avatar; 35 | 36 | private String description; 37 | 38 | private Boolean isInternal; 39 | 40 | private Integer status; 41 | 42 | private LocalDateTime createTime; 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/dto/UserGroupTree.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.dto; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | import xyz.guqing.creek.model.entity.UserGroup; 6 | import xyz.guqing.creek.model.support.Tree; 7 | 8 | /** 9 | * @author guqing 10 | */ 11 | @Data 12 | @EqualsAndHashCode(callSuper = true) 13 | public class UserGroupTree extends Tree { 14 | private Integer orderIndex; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/dto/UserInfoDTO.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.dto; 2 | 3 | import java.util.Set; 4 | import lombok.Data; 5 | 6 | import java.time.LocalDateTime; 7 | import java.util.List; 8 | 9 | /** 10 | * @author guqing 11 | * @date 2020-05-29 12 | */ 13 | @Data 14 | public class UserInfoDTO { 15 | private Long id; 16 | 17 | /** 18 | * 用户名 19 | */ 20 | private String username; 21 | 22 | private String nickname; 23 | 24 | /** 25 | * 用户组 26 | */ 27 | private Long groupId; 28 | 29 | private String groupName; 30 | 31 | private List roleIds; 32 | 33 | private List roleNames; 34 | 35 | private Set scopes; 36 | /** 37 | * 邮箱 38 | */ 39 | private String email; 40 | 41 | /** 42 | * 联系电话 43 | */ 44 | private String mobile; 45 | 46 | private String gender; 47 | 48 | /** 49 | * 头像 50 | */ 51 | private String avatar; 52 | 53 | /** 54 | * 描述 55 | */ 56 | private String description; 57 | 58 | /** 59 | * 最近访问时间 60 | */ 61 | private LocalDateTime lastLoginTime; 62 | 63 | /** 64 | * 状态 0锁定 1有效 65 | */ 66 | private Integer status; 67 | 68 | private LocalDateTime createTime; 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/dto/UserLoginLogDTO.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.dto; 2 | 3 | import lombok.Data; 4 | import xyz.guqing.creek.model.entity.UserLoginLog; 5 | import xyz.guqing.creek.model.support.OutputConverter; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | /** 10 | * @author guqing 11 | * @date 2020-07-17 12 | */ 13 | @Data 14 | public class UserLoginLogDTO implements OutputConverter { 15 | private Long id; 16 | 17 | private String username; 18 | 19 | private LocalDateTime loginTime; 20 | 21 | private String location; 22 | 23 | private String ip; 24 | 25 | private String system; 26 | 27 | private String browser; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/entity/ActionLog.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.FieldFill; 4 | import com.baomidou.mybatisplus.annotation.TableField; 5 | import com.baomidou.mybatisplus.annotation.TableName; 6 | import lombok.Data; 7 | import lombok.experimental.Accessors; 8 | 9 | import java.time.LocalDateTime; 10 | 11 | /** 12 | *

13 | * 用户操作日志表 14 | *

15 | * 16 | * @author guqing 17 | * @since 2020-08-19 18 | */ 19 | @Data 20 | @Accessors(chain = true) 21 | @TableName("action_log") 22 | public class ActionLog { 23 | 24 | private static final long serialVersionUID = 1L; 25 | private Long id; 26 | /** 27 | * 操作用户 28 | */ 29 | private String username; 30 | 31 | /** 32 | * 操作内容 33 | */ 34 | private String operation; 35 | 36 | /** 37 | * 执行时间,单位毫秒 38 | */ 39 | private Long executionTime; 40 | 41 | /** 42 | * 操作方法 43 | */ 44 | private String method; 45 | 46 | /** 47 | * 方法参数 48 | */ 49 | private String params; 50 | 51 | /** 52 | * 操作者IP 53 | */ 54 | private String ip; 55 | 56 | /** 57 | * 操作地点 58 | */ 59 | private String location; 60 | 61 | @TableField(value = "create_time", fill = FieldFill.INSERT) 62 | private LocalDateTime createTime; 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/entity/ApiResource.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | 7 | /** 8 | * @author guqing 9 | * @since 2022-01-12 10 | */ 11 | @Data 12 | @TableName("api_resource") 13 | @EqualsAndHashCode(callSuper = true) 14 | public class ApiResource extends BaseEntity { 15 | 16 | private String name; 17 | private String displayName; 18 | private String description; 19 | private Long sortIndex; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/entity/ApiScope.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | 7 | /** 8 | * @author guqing 9 | * @since 2022-01-12 10 | */ 11 | @Data 12 | @TableName("api_scope") 13 | @EqualsAndHashCode(callSuper = true) 14 | public class ApiScope extends BaseEntity { 15 | 16 | private String name; 17 | private String displayName; 18 | private String description; 19 | private Long resourceId; 20 | private Long sortIndex; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/entity/BaseEntity.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.FieldFill; 4 | import com.baomidou.mybatisplus.annotation.IdType; 5 | import com.baomidou.mybatisplus.annotation.TableField; 6 | import com.baomidou.mybatisplus.annotation.TableId; 7 | import com.fasterxml.jackson.annotation.JsonIgnore; 8 | import lombok.Data; 9 | 10 | import java.io.Serializable; 11 | import java.time.LocalDateTime; 12 | 13 | /** 14 | * 基础实体 15 | * FieldFill填充策略 16 | * DEFAULT 默认不处理 17 | * INSERT 插入填充字段 18 | * UPDATE 更新填充字段 19 | * INSERT_UPDATE 插入和更新填充字段 20 | * @author guqing 21 | * @date 2020-04-09 13:58 22 | */ 23 | @Data 24 | public class BaseEntity implements Serializable { 25 | @TableField(value = "id") 26 | @TableId(type = IdType.AUTO) 27 | private Long id; 28 | 29 | @TableField(value = "create_time", fill = FieldFill.INSERT) 30 | private LocalDateTime createTime; 31 | 32 | @TableField(value = "modify_time", fill = FieldFill.INSERT_UPDATE) 33 | @JsonIgnore 34 | private LocalDateTime modifyTime; 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/entity/Credentials.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.FieldFill; 4 | import com.baomidou.mybatisplus.annotation.IdType; 5 | import com.baomidou.mybatisplus.annotation.TableField; 6 | import com.baomidou.mybatisplus.annotation.TableId; 7 | import java.time.LocalDateTime; 8 | import lombok.Data; 9 | 10 | /** 11 | * @author guqing 12 | * @since 2022-01-14 13 | */ 14 | @Data 15 | public class Credentials { 16 | 17 | @TableField(value = "id") 18 | @TableId(type = IdType.ASSIGN_UUID) 19 | private Long id; 20 | 21 | private String token; 22 | 23 | private String remark; 24 | 25 | private LocalDateTime expiredAt; 26 | 27 | @TableField(value = "create_time", fill = FieldFill.INSERT) 28 | private LocalDateTime createTime; 29 | 30 | @TableField(value = "modify_time", fill = FieldFill.INSERT_UPDATE) 31 | private LocalDateTime modifyTime; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/entity/Menu.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import lombok.experimental.Accessors; 7 | 8 | /** 9 | *

10 | * 菜单表 11 | *

12 | * 13 | * @author guqing 14 | * @since 2020-08-19 15 | */ 16 | @Data 17 | @EqualsAndHashCode(callSuper = true) 18 | @Accessors(chain = true) 19 | @TableName("menu") 20 | public class Menu extends BaseEntity { 21 | 22 | private static final long serialVersionUID = 1L; 23 | 24 | /** 25 | * 上级菜单ID 26 | */ 27 | private Long parentId; 28 | 29 | /** 30 | * 菜单的标题 31 | */ 32 | private String title; 33 | 34 | /** 35 | * 组件名称 36 | */ 37 | private String name; 38 | 39 | /** 40 | * 对应路由path 41 | */ 42 | private String path; 43 | 44 | /** 45 | * 重定向到路径 46 | */ 47 | private String redirect; 48 | 49 | /** 50 | * 对应路由组件component 51 | */ 52 | private String component; 53 | 54 | /** 55 | * 图标 56 | */ 57 | private String icon; 58 | 59 | private Integer keepAlive; 60 | 61 | /** 62 | * 控制路由和子路由是否显示在 sidebar 63 | */ 64 | private Integer hidden; 65 | 66 | /** 67 | * 排序 68 | */ 69 | private Long sortIndex; 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/entity/OauthAccessToken.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import com.baomidou.mybatisplus.annotation.TableName; 6 | import lombok.Data; 7 | 8 | @Data 9 | @TableName("oauth_access_token") 10 | public class OauthAccessToken { 11 | @TableId(type = IdType.INPUT) 12 | private String tokenId; 13 | 14 | private String token; 15 | 16 | private String authenticationId; 17 | 18 | private String authentication; 19 | 20 | private String refreshToken; 21 | 22 | private String userName; 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/entity/OauthRefreshToken.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import lombok.Data; 5 | 6 | /** 7 | * @author guqing 8 | * @since 2022-01-23 9 | */ 10 | @Data 11 | @TableName("oauth_refresh_token") 12 | public class OauthRefreshToken { 13 | private String tokenId; 14 | private String token; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/entity/Role.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableLogic; 4 | import com.baomidou.mybatisplus.annotation.TableName; 5 | import lombok.Data; 6 | import lombok.EqualsAndHashCode; 7 | import lombok.experimental.Accessors; 8 | 9 | /** 10 | *

11 | * 角色表 12 | *

13 | * 14 | * @author guqing 15 | * @since 2020-08-19 16 | */ 17 | @Data 18 | @EqualsAndHashCode(callSuper = true) 19 | @Accessors(chain = true) 20 | @TableName("role") 21 | public class Role extends BaseEntity { 22 | 23 | private static final long serialVersionUID = 1L; 24 | 25 | /** 26 | * 角色名称 27 | */ 28 | private String roleName; 29 | 30 | /** 31 | * 角色描述 32 | */ 33 | private String remark; 34 | 35 | /** 36 | * 是否为系统内置 37 | */ 38 | private Boolean isInternal; 39 | 40 | @TableLogic 41 | private Integer deleted; 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/entity/RoleResource.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import com.baomidou.mybatisplus.annotation.TableName; 6 | import java.util.Collection; 7 | import lombok.Data; 8 | import lombok.experimental.Accessors; 9 | 10 | /** 11 | *

12 | * 角色资源表,存储角色关联的菜单和api资源 13 | *

14 | * 15 | * @author guqing 16 | * @since 2020-08-19 17 | */ 18 | @Data 19 | @Accessors(chain = true) 20 | @TableName("role_resource") 21 | public class RoleResource { 22 | 23 | private static final long serialVersionUID = 1L; 24 | 25 | @TableId(type = IdType.AUTO) 26 | private Long id; 27 | 28 | private Long roleId; 29 | 30 | private String scope; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/entity/User.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableLogic; 4 | import com.baomidou.mybatisplus.annotation.TableName; 5 | import java.util.List; 6 | import lombok.Data; 7 | import lombok.EqualsAndHashCode; 8 | import lombok.experimental.Accessors; 9 | 10 | import java.time.LocalDateTime; 11 | 12 | /** 13 | *

14 | * 用户表 15 | *

16 | * 17 | * @author guqing 18 | * @since 2020-08-19 19 | */ 20 | @Data 21 | @EqualsAndHashCode(callSuper = true) 22 | @Accessors(chain = true) 23 | @TableName("user") 24 | public class User extends BaseEntity { 25 | 26 | private static final long serialVersionUID = 1L; 27 | 28 | /** 29 | * 用户名 30 | */ 31 | private String username; 32 | 33 | /** 34 | * 密码 35 | */ 36 | private String password; 37 | 38 | /** 39 | * 昵称 40 | */ 41 | private String nickname; 42 | 43 | /** 44 | * 用户组 45 | */ 46 | private Long groupId; 47 | 48 | /** 49 | * 邮箱 50 | */ 51 | private String email; 52 | 53 | /** 54 | * 联系电话 55 | */ 56 | private String mobile; 57 | 58 | /** 59 | * 性别 60 | */ 61 | private String gender; 62 | 63 | private String roleIds; 64 | 65 | /** 66 | * 头像 67 | */ 68 | private String avatar; 69 | 70 | /** 71 | * 描述 72 | */ 73 | private String description; 74 | 75 | /** 76 | * 最近访问时间 77 | */ 78 | private LocalDateTime lastLoginTime; 79 | 80 | /** 81 | * 状态 0锁定 1有效 82 | */ 83 | private Integer status; 84 | 85 | /** 86 | * 是否为系统内置 87 | */ 88 | private Boolean isInternal; 89 | 90 | /** 91 | * 删除状态:0未删除,1已删除 92 | */ 93 | @TableLogic 94 | private Integer deleted; 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/entity/UserConnection.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.entity; 2 | 3 | import lombok.Data; 4 | import lombok.experimental.Accessors; 5 | 6 | /** 7 | *

8 | * 系统用户社交账户关联表 9 | *

10 | * 11 | * @author guqing 12 | * @since 2020-05-21 13 | */ 14 | @Data 15 | @Accessors(chain = true) 16 | public class UserConnection { 17 | 18 | private static final long serialVersionUID = 1L; 19 | 20 | /** 21 | * Violet系统用户id 22 | */ 23 | private Long userId; 24 | 25 | /** 26 | * 第三方平台名称 27 | */ 28 | private String providerName; 29 | 30 | /** 31 | * 第三方平台账户ID 32 | */ 33 | private String providerUserId; 34 | 35 | /** 36 | * 第三方平台用户名 37 | */ 38 | private String providerUserName; 39 | 40 | /** 41 | * 第三方平台昵称 42 | */ 43 | private String nickName; 44 | 45 | /** 46 | * 第三方平台头像 47 | */ 48 | private String avatar; 49 | 50 | /** 51 | * 地址 52 | */ 53 | private String location; 54 | 55 | /** 56 | * 备注 57 | */ 58 | private String remark; 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/entity/UserGroup.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import lombok.experimental.Accessors; 7 | 8 | /** 9 | *

10 | * 用户分组表 11 | *

12 | * 13 | * @author guqing 14 | * @since 2020-08-19 15 | */ 16 | @Data 17 | @EqualsAndHashCode(callSuper = true) 18 | @Accessors(chain = true) 19 | @TableName("user_group") 20 | public class UserGroup extends BaseEntity { 21 | 22 | private static final long serialVersionUID = 1L; 23 | 24 | /** 25 | * 上级分组id 26 | */ 27 | private Long parentId; 28 | 29 | /** 30 | * 分组名称 31 | */ 32 | private String groupName; 33 | 34 | /** 35 | * 排序 36 | */ 37 | private Long sortIndex; 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/entity/UserLoginLog.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import lombok.Data; 5 | import lombok.experimental.Accessors; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | /** 10 | *

11 | * 登录日志表 12 | *

13 | * 14 | * @author guqing 15 | * @since 2020-08-19 16 | */ 17 | @Data 18 | @Accessors(chain = true) 19 | @TableName("user_login_log") 20 | public class UserLoginLog { 21 | 22 | private static final long serialVersionUID = 1L; 23 | private Long id; 24 | /** 25 | * 用户名 26 | */ 27 | private String username; 28 | 29 | /** 30 | * 登录时间 31 | */ 32 | private LocalDateTime loginTime; 33 | 34 | /** 35 | * 登录地点 36 | */ 37 | private String location; 38 | 39 | /** 40 | * IP地址 41 | */ 42 | private String ip; 43 | 44 | /** 45 | * 操作系统 46 | */ 47 | private String system; 48 | 49 | /** 50 | * 浏览器 51 | */ 52 | private String browser; 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/enums/GenderEnum.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.enums; 2 | 3 | /** 4 | * @author guqing 5 | * @date 2020-06-03 6 | */ 7 | public enum GenderEnum { 8 | /** 9 | * 用户性别,男,女,未知 10 | */ 11 | MALE, 12 | FEMALE, 13 | UNKNOWN; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/enums/MenuType.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.enums; 2 | 3 | /** 4 | * @author guqing 5 | * @date 2020-06-04 6 | */ 7 | public enum MenuType { 8 | /** 9 | * 菜单类型,0菜单,1按钮 10 | */ 11 | MENU("0"), 12 | BUTTON("1"); 13 | private String value; 14 | 15 | MenuType(String value) { 16 | this.value = value; 17 | } 18 | 19 | public String getValue() { 20 | return value; 21 | } 22 | 23 | public void setValue(String value) { 24 | this.value = value; 25 | } 26 | 27 | public static String valueFrom(String type) { 28 | for(MenuType menuType : values()) { 29 | if(menuType.getValue().equals(type)) { 30 | return type; 31 | } 32 | } 33 | return MENU.getValue(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/enums/ResultEntityEnum.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.enums; 2 | 3 | /** 4 | * @author guqing 5 | * @date 2020-04-15 10:24 6 | */ 7 | public enum ResultEntityEnum { 8 | /** 9 | * 一些返回值枚举 10 | */ 11 | SUCCESS("00000", "成功"), 12 | USERNAME_CONFLICT("A0110", "用户名已经存在"), 13 | USER_PASSWORD_ERROR("A0120", "用户密码不正确"), 14 | USER_LOGIN_EXCEPTION("A0200", "用户登录异常"), 15 | USER_RESOURCE_EXCEPTION("A0600", "用户资源异常"), 16 | USER_NOT_FOUND("A0201", "用户账户不存在"), 17 | CERTIFICATE_VERIFICATION_FAILED("A0220", "用户身份校验失败"), 18 | UNAUTHORIZED("A0300", "未经授权,无操作权限"), 19 | ACCESS_DENIED("A0320", "用户访问被拒绝"), 20 | BAD_ARGUMENT("A0400", "用户请求参数错误"), 21 | BAD_ARGUMENT_VALUE("A0410", "用户必填参数为空"), 22 | USER_UPLOAD_ERROR("A0700", "用户上传文件异常"), 23 | UN_SUPPORTED_MEDIA_TYPE("A0701", "不支持的媒体类型"), 24 | SERVER_ERROR("B0001", "系统执行出错"), 25 | SERVER_EXECUTION_TIMEOUT("B0100", "系统执行超时"), 26 | RPC_FAILED("C0001", "调用第三方服务出错"), 27 | RPC_TIMEOUT("C0200", "第三方系统执行超时"), 28 | NOTIFICATION_ERROR("C0500", "通知服务出错"), 29 | REPEAT_OPS("A0506", "用户重复请求"); 30 | 31 | 32 | private String code; 33 | private String desc; 34 | 35 | ResultEntityEnum(String code, String desc) { 36 | this.code = code; 37 | this.desc = desc; 38 | } 39 | 40 | public String getCode() { 41 | return code; 42 | } 43 | 44 | public void setCode(String code) { 45 | this.code = code; 46 | } 47 | 48 | public String getDesc() { 49 | return desc; 50 | } 51 | 52 | public void setDesc(String desc) { 53 | this.desc = desc; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/enums/UserStatusEnum.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.enums; 2 | 3 | /** 4 | * @author guqing 5 | * @date 2020-06-03 6 | */ 7 | public enum UserStatusEnum { 8 | /** 9 | * 用户状态 10 | */ 11 | NORMAL(0), 12 | DISABLE(1); 13 | 14 | private Integer value; 15 | 16 | UserStatusEnum(Integer value) { 17 | this.value = value; 18 | } 19 | 20 | public Integer getValue() { 21 | return value; 22 | } 23 | 24 | public void setValue(Integer value) { 25 | this.value = value; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/params/ActionLogQuery.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.params; 2 | 3 | import lombok.Data; 4 | 5 | import java.time.LocalDateTime; 6 | 7 | /** 8 | * @author guqing 9 | * @date 2020-07-11 10 | */ 11 | @Data 12 | public class ActionLogQuery { 13 | private String username; 14 | /** 15 | * 操作内容 16 | */ 17 | private String operation; 18 | 19 | private String location; 20 | 21 | /** 22 | * 日志创建开始时间 23 | */ 24 | private LocalDateTime createFrom; 25 | 26 | /** 27 | * 日志创建结束时间 28 | */ 29 | private LocalDateTime createTo; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/params/BindUserParam.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.params; 2 | 3 | import jakarta.validation.constraints.NotBlank; 4 | import jakarta.validation.constraints.NotNull; 5 | import jakarta.validation.constraints.Pattern; 6 | import jakarta.validation.constraints.Size; 7 | import lombok.Data; 8 | import xyz.guqing.creek.model.constant.RegexpConstant; 9 | 10 | 11 | /** 12 | * @author guqing 13 | * @date 2020-07-15 14 | */ 15 | @Data 16 | public class BindUserParam { 17 | @NotBlank(message = "邮箱地址不能为空") 18 | @Pattern(regexp = RegexpConstant.EMAIL, message = "邮箱地址格式不正确") 19 | private String email; 20 | 21 | @NotBlank(message = "密码不能为空") 22 | @Size(min = 3, max = 16, message = "密码字符长度必须在 {min}-{max} 之间") 23 | private String password; 24 | 25 | @NotBlank(message = "验证码不能为空") 26 | private String captcha; 27 | 28 | @NotNull(message = "第三方认证用户信息不能为空") 29 | private SocialUserParam socialUserParam; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/params/ChangePasswordParam.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.params; 2 | 3 | import jakarta.validation.constraints.NotBlank; 4 | import jakarta.validation.constraints.Size; 5 | import lombok.Data; 6 | 7 | 8 | /** 9 | * @author guqing 10 | * @date 2020-10-14 11 | */ 12 | @Data 13 | public class ChangePasswordParam { 14 | @NotBlank(message = "原始密码不能为空") 15 | private String oldPassword; 16 | @NotBlank(message = "新密码不能为空") 17 | @Size(max = 16, message = "密码字符长度不能超过 {max}") 18 | private String newPassword; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/params/CredentialsParam.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.params; 2 | 3 | import jakarta.validation.constraints.NotBlank; 4 | import jakarta.validation.constraints.NotNull; 5 | import java.time.LocalDateTime; 6 | import java.util.Set; 7 | import lombok.Data; 8 | import xyz.guqing.creek.model.entity.Credentials; 9 | import xyz.guqing.creek.model.support.InputConverter; 10 | 11 | /** 12 | * @author guqing 13 | * @since 2022-01-17 14 | */ 15 | @Data 16 | public class CredentialsParam implements InputConverter { 17 | 18 | @NotBlank(message = "备注不能为空") 19 | private String remark; 20 | 21 | @NotNull(message = "权限域不能为空") 22 | private Set scopes; 23 | 24 | @NotNull(message = "过期时间不能为空") 25 | private LocalDateTime expiredAt; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/params/LoginLogParam.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.params; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import lombok.Data; 5 | 6 | import java.time.LocalDateTime; 7 | 8 | /** 9 | * @author guqing 10 | * @date 2020-07-17 11 | */ 12 | @Data 13 | @JsonIgnoreProperties(ignoreUnknown = true) 14 | public class LoginLogParam { 15 | private String username; 16 | private LocalDateTime createFrom; 17 | private LocalDateTime createTo; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/params/LoginParam.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.params; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import lombok.Data; 5 | 6 | /** 7 | * @author guqing 8 | * @date 2020-08-19 9 | */ 10 | @Data 11 | @JsonIgnoreProperties(ignoreUnknown = true) 12 | public class LoginParam { 13 | private String username; 14 | private String password; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/params/MenuParam.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.params; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import jakarta.validation.constraints.NotBlank; 5 | import jakarta.validation.constraints.Size; 6 | import lombok.Data; 7 | import xyz.guqing.creek.model.entity.Menu; 8 | import xyz.guqing.creek.model.enums.MenuType; 9 | import xyz.guqing.creek.model.support.InputConverter; 10 | 11 | 12 | /** 13 | * @author guqing 14 | * @date 2020-06-06 15 | */ 16 | @Data 17 | @JsonIgnoreProperties(ignoreUnknown = true) 18 | public class MenuParam implements InputConverter { 19 | private Long id; 20 | 21 | private Long parentId; 22 | 23 | @NotBlank(message = "菜单标题不能为空") 24 | @Size(max = 150, message = "菜单标题不能字符长度不能大于 {max}") 25 | private String title; 26 | 27 | private String type; 28 | 29 | private String path; 30 | 31 | private String redirect; 32 | 33 | private String name; 34 | 35 | private String component; 36 | 37 | private String perms; 38 | 39 | private String icon; 40 | 41 | private Boolean hidden; 42 | 43 | private Boolean keepAlive; 44 | 45 | private Long sortIndex; 46 | 47 | @Override 48 | public Menu convertTo() { 49 | if(parentId == null) { 50 | parentId = 0L; 51 | } 52 | if(sortIndex == null) { 53 | sortIndex = 0L; 54 | } 55 | 56 | if(keepAlive == null) { 57 | keepAlive = false; 58 | } 59 | 60 | type = MenuType.valueFrom(type); 61 | 62 | return InputConverter.super.convertTo(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/params/MenuQuery.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.params; 2 | 3 | import lombok.Data; 4 | import xyz.guqing.creek.model.entity.Menu; 5 | import xyz.guqing.creek.model.support.InputConverter; 6 | 7 | /** 8 | * @author guqing 9 | * @date 2020-06-04 10 | */ 11 | @Data 12 | public class MenuQuery implements InputConverter { 13 | private Long orderIndex; 14 | private String type; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/params/RoleParam.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.params; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import jakarta.validation.constraints.NotBlank; 5 | import jakarta.validation.constraints.NotNull; 6 | import jakarta.validation.constraints.Size; 7 | import lombok.Data; 8 | import xyz.guqing.creek.model.entity.Role; 9 | import xyz.guqing.creek.model.support.InputConverter; 10 | import java.util.Set; 11 | 12 | /** 13 | * @author guqing 14 | * @date 2020-06-09 15 | */ 16 | @Data 17 | @JsonIgnoreProperties(ignoreUnknown = true) 18 | public class RoleParam implements InputConverter { 19 | private Long id; 20 | 21 | @NotBlank(message = "角色名称不能为空") 22 | @Size(max = 140, message = "角色名称字符长度不能超过 {max}") 23 | private String roleName; 24 | 25 | private String remark; 26 | 27 | @NotNull 28 | private Set authorities; 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/params/RoleQuery.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.params; 2 | 3 | import lombok.Data; 4 | import xyz.guqing.creek.model.support.PageQuery; 5 | 6 | /** 7 | * @author guqing 8 | * @date 2020-06-05 9 | */ 10 | @Data 11 | public class RoleQuery { 12 | private Long id; 13 | private String roleName; 14 | private String remark; 15 | private String createTime; 16 | private PageQuery pageQuery = new PageQuery(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/params/SocialUserParam.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.params; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import lombok.Data; 5 | import me.zhyd.oauth.config.AuthSource; 6 | import me.zhyd.oauth.enums.AuthUserGender; 7 | import me.zhyd.oauth.model.AuthUser; 8 | import xyz.guqing.creek.model.support.InputConverter; 9 | 10 | /** 11 | * @author guqing 12 | * @date 2020-07-28 13 | */ 14 | @Data 15 | @JsonIgnoreProperties(ignoreUnknown = true) 16 | public class SocialUserParam implements InputConverter { 17 | private String uuid; 18 | private String username; 19 | private String nickname; 20 | private String avatar; 21 | private String blog; 22 | private String company; 23 | private String location; 24 | private String email; 25 | private String remark; 26 | private AuthUserGender gender; 27 | private AuthSource source; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/params/UserGroupParam.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.params; 2 | 3 | import jakarta.validation.constraints.NotBlank; 4 | import jakarta.validation.constraints.Size; 5 | import lombok.Data; 6 | import xyz.guqing.creek.model.entity.UserGroup; 7 | import xyz.guqing.creek.model.support.InputConverter; 8 | 9 | 10 | /** 11 | * @author guqing 12 | * @date 2020-06-06 13 | */ 14 | @Data 15 | public class UserGroupParam implements InputConverter { 16 | private Long id; 17 | 18 | private Long parentId; 19 | 20 | @NotBlank(message = "用户组名称不能为空") 21 | @Size(max = 150, message = "用户组名称字符长度不能超过 {max}") 22 | private String groupName; 23 | 24 | private Long sortIndex; 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/params/UserParam.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.params; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import lombok.Data; 5 | import xyz.guqing.creek.model.constant.RegexpConstant; 6 | import xyz.guqing.creek.model.entity.User; 7 | import xyz.guqing.creek.model.support.CreateCheck; 8 | import xyz.guqing.creek.model.support.InputConverter; 9 | import xyz.guqing.creek.model.support.UpdateCheck; 10 | 11 | import jakarta.validation.constraints.NotBlank; 12 | import jakarta.validation.constraints.NotEmpty; 13 | import jakarta.validation.constraints.Pattern; 14 | import jakarta.validation.constraints.Size; 15 | import java.util.List; 16 | 17 | /** 18 | * @author guqing 19 | * @date 2020-06-01 20 | */ 21 | @Data 22 | @JsonIgnoreProperties(ignoreUnknown = true) 23 | public class UserParam implements InputConverter { 24 | private Long id; 25 | 26 | @NotBlank(message = "用户名不能为空", groups = {CreateCheck.class, UpdateCheck.class}) 27 | @Size(max = 100, message = "用户名字符长度不能超过 {max}") 28 | private String username; 29 | /** 30 | * 密码 31 | */ 32 | @NotBlank(message = "用户密码不能为空", groups = {CreateCheck.class}) 33 | @Size(min = 3, max = 16, message = "密码长度必须在 {min}-{max} 字符之间") 34 | private String password; 35 | 36 | /** 37 | * 邮箱 38 | */ 39 | @Pattern(regexp = RegexpConstant.EMAIL, message = "邮箱地址格式不正确") 40 | private String email; 41 | 42 | /** 43 | * 联系电话 44 | */ 45 | @Pattern(regexp = RegexpConstant.MOBILE, message = "手机号码格式不正确") 46 | private String mobile; 47 | 48 | /** 49 | * 头像 50 | */ 51 | private String avatar; 52 | 53 | /** 54 | * 描述 55 | */ 56 | @Size(max = 150, message = "个性签名字符长度不能大于 {max}") 57 | private String description; 58 | 59 | @NotEmpty(message = "用户角色不能为空", groups = {CreateCheck.class, UpdateCheck.class}) 60 | private List roleIds; 61 | 62 | private Long groupId; 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/params/UserProfileParam.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.params; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import jakarta.validation.constraints.NotBlank; 5 | import jakarta.validation.constraints.Pattern; 6 | import jakarta.validation.constraints.Size; 7 | import lombok.Data; 8 | import xyz.guqing.creek.model.constant.RegexpConstant; 9 | import xyz.guqing.creek.model.entity.User; 10 | import xyz.guqing.creek.model.support.InputConverter; 11 | 12 | 13 | /** 14 | * 用户个人主页参数 15 | * @author guqing 16 | * @date 2020-10-12 17 | */ 18 | @Data 19 | @JsonIgnoreProperties(ignoreUnknown = true) 20 | public class UserProfileParam implements InputConverter { 21 | @NotBlank(message = "昵称不能为空") 22 | @Size(max = 30, message = "昵称字符长度不能超过 {max}") 23 | private String nickname; 24 | /** 25 | * 邮箱 26 | */ 27 | @Pattern(regexp = RegexpConstant.EMAIL, message = "邮箱地址格式不正确") 28 | private String email; 29 | 30 | /** 31 | * 联系电话 32 | */ 33 | @Pattern(regexp = RegexpConstant.MOBILE, message = "手机号码格式不正确") 34 | private String mobile; 35 | 36 | /** 37 | * 描述 38 | */ 39 | @Size(max = 150, message = "个性签名字符长度不能大于 {max}") 40 | private String description; 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/params/UserQuery.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.params; 2 | 3 | import lombok.Data; 4 | 5 | import java.time.LocalDateTime; 6 | 7 | /** 8 | * @author guqing 9 | * @date 2020-05-30 10 | */ 11 | @Data 12 | public class UserQuery { 13 | private String username; 14 | private String nickname; 15 | private Long groupId; 16 | private String gender; 17 | private Integer status; 18 | private String mobile; 19 | private String groupName; 20 | private LocalDateTime createTimeFrom; 21 | private LocalDateTime createTimeTo; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/properties/ThreadPoolProperties.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.properties; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | 6 | /** 7 | * @author guqing 8 | * @date 2020-04-21 10:02 9 | */ 10 | @Data 11 | @ConfigurationProperties(prefix = "creek.thread.pool") 12 | public class ThreadPoolProperties { 13 | private Integer corePoolSize = 8; 14 | private Integer maximumPoolSize = 100; 15 | private Integer queueSize = 100000; 16 | private Integer keepAliveTime = 10; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/support/CreateCheck.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.support; 2 | 3 | /** 4 | * 创建时参数分组校验 5 | * 6 | * @author guqing 7 | * @date 2020-7-13 8 | */ 9 | public interface CreateCheck { 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/support/InputConverter.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.support; 2 | 3 | import org.springframework.lang.Nullable; 4 | import xyz.guqing.creek.utils.ReflectionUtils; 5 | 6 | import java.lang.reflect.ParameterizedType; 7 | import java.util.Objects; 8 | 9 | /** 10 | * Converter interface for input DTO. 11 | * 12 | * @author johnniang 13 | */ 14 | public interface InputConverter { 15 | 16 | /** 17 | * Convert to domain.(shallow) 18 | * 19 | * @return new domain with same value(not null) 20 | */ 21 | @SuppressWarnings("unchecked") 22 | default DOMAIN convertTo() { 23 | // Get parameterized type 24 | ParameterizedType currentType = parameterizedType(); 25 | 26 | // Assert not equal 27 | Objects.requireNonNull(currentType, "Cannot fetch actual type because parameterized type is null"); 28 | 29 | Class domainClass = (Class) currentType.getActualTypeArguments()[0]; 30 | 31 | return BeanUtils.transformFrom(this, domainClass); 32 | } 33 | 34 | /** 35 | * Update a domain by dto.(shallow) 36 | * 37 | * @param domain updated domain 38 | */ 39 | default void update(DOMAIN domain) { 40 | BeanUtils.updateProperties(this, domain); 41 | } 42 | 43 | /** 44 | * Get parameterized type. 45 | * 46 | * @return parameterized type or null 47 | */ 48 | @Nullable 49 | default ParameterizedType parameterizedType() { 50 | return ReflectionUtils.getParameterizedType(InputConverter.class, this.getClass()); 51 | } 52 | } 53 | 54 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/support/OutputConverter.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.support; 2 | 3 | import org.springframework.lang.NonNull; 4 | 5 | /** 6 | * Converter interface for output DTO. 7 | * 8 | * The implementation type must be equal to DTO type 9 | * 10 | * @param the implementation class type 11 | * @param domain type 12 | * @author johnniang 13 | */ 14 | public interface OutputConverter, DOMAIN> { 15 | 16 | /** 17 | * Convert from domain.(shallow) 18 | * 19 | * @param domain domain data 20 | * @return converted dto data 21 | */ 22 | @SuppressWarnings("unchecked") 23 | @NonNull 24 | default T convertFrom(@NonNull DOMAIN domain) { 25 | 26 | BeanUtils.updateProperties(domain, this); 27 | 28 | return (T) this; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/support/PageQuery.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.support; 2 | 3 | import lombok.Data; 4 | import lombok.ToString; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @author guqing 10 | */ 11 | @Data 12 | @ToString 13 | public class PageQuery implements Serializable { 14 | 15 | private static final long serialVersionUID = -4869594085374385813L; 16 | /** 17 | * 当前页面数据量 18 | */ 19 | private Long pageSize = 10L; 20 | /** 21 | * 当前页码 22 | */ 23 | private Long current = 1L; 24 | /** 25 | * 排序字段 26 | */ 27 | private String field; 28 | /** 29 | * 排序规则,asc升序,desc降序 30 | */ 31 | private String order; 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/support/Tree.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.support; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import lombok.Data; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * @author guqing 11 | */ 12 | @Data 13 | @JsonInclude(JsonInclude.Include.NON_NULL) 14 | public class Tree { 15 | 16 | private String id; 17 | 18 | private String title; 19 | 20 | private String key; 21 | 22 | private String value; 23 | 24 | private List> children; 25 | 26 | private String parentId; 27 | 28 | private String perms; 29 | 30 | private boolean hasParent = false; 31 | 32 | private boolean hasChildren = false; 33 | 34 | public void initChildren() { 35 | this.children = new ArrayList<>(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/model/support/UpdateCheck.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.model.support; 2 | 3 | /** 4 | * 更新时参数分组校验 5 | * 6 | * @author guqing 7 | * @date 2020-7-13 8 | */ 9 | public interface UpdateCheck { 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/security/handler/JwtAccessDeniedHandler.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.security.handler; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import jakarta.servlet.ServletException; 5 | import jakarta.servlet.http.HttpServletRequest; 6 | import jakarta.servlet.http.HttpServletResponse; 7 | import org.springframework.security.access.AccessDeniedException; 8 | import org.springframework.security.web.access.AccessDeniedHandler; 9 | import org.springframework.stereotype.Component; 10 | import xyz.guqing.creek.model.support.ResultEntity; 11 | 12 | import java.io.IOException; 13 | 14 | /** 15 | * @author guqing 16 | * @date 2019-12-22 24:53 17 | */ 18 | @Component 19 | public class JwtAccessDeniedHandler implements AccessDeniedHandler { 20 | 21 | @Override 22 | public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, 23 | ServletException { 24 | httpServletResponse.setContentType("application/json;charset=UTF-8"); 25 | // 访问被拒绝 26 | httpServletResponse.getWriter().write(JSON.toJSONString(ResultEntity.unauthorized())); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/security/handler/JwtAuthenticationEntryPoint.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.security.handler; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import jakarta.servlet.ServletException; 5 | import jakarta.servlet.http.HttpServletRequest; 6 | import jakarta.servlet.http.HttpServletResponse; 7 | import org.springframework.security.core.AuthenticationException; 8 | import org.springframework.security.web.AuthenticationEntryPoint; 9 | import org.springframework.stereotype.Component; 10 | import xyz.guqing.creek.model.support.ResultEntity; 11 | 12 | import java.io.IOException; 13 | 14 | 15 | /** 16 | * @author guqing 17 | * @date 2019-12-22 24:53 18 | */ 19 | @Component 20 | public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { 21 | 22 | @Override 23 | public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, 24 | ServletException { 25 | httpServletResponse.setContentType("application/json;charset=UTF-8"); 26 | //Need Authorities! 27 | httpServletResponse.getWriter().write(JSON.toJSONString(ResultEntity.unauthorized())); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/security/handler/JwtAuthenticationFailureHandler.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.security.handler; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import jakarta.servlet.http.HttpServletRequest; 5 | import jakarta.servlet.http.HttpServletResponse; 6 | import java.io.IOException; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.security.core.AuthenticationException; 9 | import org.springframework.security.web.authentication.AuthenticationFailureHandler; 10 | import xyz.guqing.creek.model.support.ResultEntity; 11 | 12 | 13 | /** 14 | * @author guqing 15 | * @date 2019-12-22 24:53 16 | */ 17 | @Slf4j 18 | public class JwtAuthenticationFailureHandler implements AuthenticationFailureHandler { 19 | 20 | @Override 21 | public void onAuthenticationFailure(HttpServletRequest httpServletRequest, 22 | HttpServletResponse httpServletResponse, AuthenticationException e) 23 | throws IOException { 24 | log.error(e.getMessage(), e); 25 | httpServletResponse.setContentType("application/json;charset=UTF-8"); 26 | // 登陆失败 27 | httpServletResponse.getWriter() 28 | .write(JSON.toJSONString(ResultEntity.authorizedFailed("认证失败"))); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/security/handler/JwtLogoutSuccessHandler.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.security.handler; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import jakarta.servlet.ServletException; 5 | import jakarta.servlet.http.HttpServletRequest; 6 | import jakarta.servlet.http.HttpServletResponse; 7 | import org.springframework.security.core.Authentication; 8 | import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; 9 | import org.springframework.stereotype.Component; 10 | import xyz.guqing.creek.model.support.ResultEntity; 11 | 12 | import java.io.IOException; 13 | 14 | 15 | /** 16 | * @author guqing 17 | * @date 2019-12-22 24:53 18 | */ 19 | @Component 20 | public class JwtLogoutSuccessHandler implements LogoutSuccessHandler { 21 | 22 | @Override 23 | public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, 24 | ServletException { 25 | httpServletResponse.setContentType("application/json;charset=UTF-8"); 26 | httpServletResponse.getWriter().write(JSON.toJSONString(ResultEntity.ok("注销成功"))); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/security/properties/LoginProperties.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.security.properties; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.stereotype.Component; 6 | 7 | 8 | /** 9 | * @author guqing 10 | * @date 2019-12-22 24:53 11 | */ 12 | @Data 13 | @Component 14 | @ConfigurationProperties(prefix = "auth.security.login") 15 | public class LoginProperties { 16 | private String loginUrl = "/authorize/token"; 17 | private String logoutUrl = "/authorize/logout"; 18 | /** 19 | * 社交登陆成功后跳转地址 20 | */ 21 | private String socialRedirectUrl; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/security/properties/SecurityProperties.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.security.properties; 2 | 3 | import lombok.Data; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | import org.springframework.stereotype.Component; 7 | 8 | 9 | /** 10 | * @author guqing 11 | * @date 2019-12-22 24:53 12 | */ 13 | @Data 14 | @Component 15 | @ConfigurationProperties("secure") 16 | public class SecurityProperties { 17 | private final TokenProperties tokenProperties; 18 | private final LoginProperties loginProperties; 19 | 20 | @Autowired 21 | public SecurityProperties(LoginProperties loginProperties, 22 | TokenProperties tokenProperties) { 23 | this.loginProperties = loginProperties; 24 | this.tokenProperties = tokenProperties; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/security/properties/TokenProperties.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.security.properties; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.stereotype.Component; 6 | 7 | 8 | /** 9 | * @author guqing 10 | * @date 2019-12-22 24:53 11 | */ 12 | @Data 13 | @Component 14 | @ConfigurationProperties(prefix = "auth.security.token") 15 | public class TokenProperties { 16 | /** 17 | * 30分钟(以分钟计) 18 | */ 19 | private int expireAt = 30; 20 | /** 21 | * 允许过期时间时钟偏移分钟为单位 22 | */ 23 | private long allowedClockSkewSeconds = 30; 24 | /** 25 | * JWT密码 26 | */ 27 | private String secret = "hello world"; 28 | /** 29 | * Token前缀 30 | */ 31 | private String tokenPrefix = "bearer"; 32 | /** 33 | * 存放Token的Header Key 34 | */ 35 | private String header = "Authorization"; 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/service/ActionLogService.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.service; 2 | 3 | import com.baomidou.mybatisplus.core.metadata.IPage; 4 | import com.baomidou.mybatisplus.extension.service.IService; 5 | import org.aspectj.lang.ProceedingJoinPoint; 6 | import org.springframework.scheduling.annotation.Async; 7 | import xyz.guqing.creek.model.constant.CreekConstant; 8 | import xyz.guqing.creek.model.entity.ActionLog; 9 | import xyz.guqing.creek.model.params.ActionLogQuery; 10 | import xyz.guqing.creek.model.support.PageQuery; 11 | 12 | import java.lang.reflect.Method; 13 | 14 | /** 15 | * 系统操作日志服务类 16 | * @author guqing 17 | * @date 2020-06-01 18 | */ 19 | public interface ActionLogService extends IService { 20 | 21 | /** 22 | * 异步保存操作日志 23 | * 24 | * @param point 切点 25 | * @param method Method 26 | * @param ip ip 27 | * @param operation 操作内容 28 | * @param username 操作用户 29 | * @param start 开始时间 30 | */ 31 | @Async(CreekConstant.ASYNC_POOL) 32 | void saveLog(ProceedingJoinPoint point, Method method, String ip, String operation, String username, long start); 33 | 34 | /** 35 | * 根据条件查询日志 36 | * @param logQuery 查询条件 37 | * @param pageQuery 分页 38 | * @return 返回分页查询结果 39 | */ 40 | IPage listBy(ActionLogQuery logQuery, PageQuery pageQuery); 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/service/ApiResourceService.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import java.util.List; 5 | import xyz.guqing.creek.model.dto.ApiResourceDTO; 6 | import xyz.guqing.creek.model.entity.ApiResource; 7 | 8 | /** 9 | * @author guqing 10 | * @sinceI2022-01-12 11 | */ 12 | public interface ApiResourceService extends IService { 13 | 14 | List listWithScopes(); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/service/CredentialsService.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.service; 2 | 3 | import java.util.List; 4 | import xyz.guqing.creek.model.dto.CredentialsDTO; 5 | 6 | /** 7 | * @author guqing 8 | * @since 2022-01-14 9 | */ 10 | public interface CredentialsService { 11 | 12 | List listAll(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/service/RoleResourceService.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.service; 2 | 3 | import java.util.Set; 4 | import xyz.guqing.creek.model.dto.ApiResourceDTO; 5 | import xyz.guqing.creek.model.entity.ApiScope; 6 | import xyz.guqing.creek.model.entity.RoleResource; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author guqing 12 | * @date 2020-06-09 13 | */ 14 | public interface RoleResourceService { 15 | /** 16 | * 根据角色id查询角色和菜单的关联关系 17 | * @param roleId 角色id 18 | * @return 查询到返回集合信息否则返回空集合 19 | */ 20 | List listByRoleId(Long roleId); 21 | 22 | List getResourceByRoleId(Long roleId); 23 | 24 | /** 25 | * 根据角色id删除角色资源关联 26 | * 27 | * @param roleId 菜单id集合 28 | */ 29 | void deleteByRoleId(Long roleId); 30 | 31 | /** 32 | * 根据角色id查询角色包含的api scope集合 33 | * 34 | * @param roleIds 角色id 35 | * @return 返回角色拥有的api scope 36 | */ 37 | List listScopesByRoleIds(List roleIds); 38 | 39 | List listScopesByUsername(String username); 40 | 41 | Set listScopeNameByRoleIds(List roleIds); 42 | 43 | void createOrUpdate(Long roleId, Set authorities); 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/service/RoleService.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.service; 2 | 3 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 4 | import com.baomidou.mybatisplus.extension.service.IService; 5 | import xyz.guqing.creek.model.dto.RoleDTO; 6 | import xyz.guqing.creek.model.entity.Role; 7 | import xyz.guqing.creek.model.params.RoleQuery; 8 | 9 | import java.util.List; 10 | import java.util.Set; 11 | 12 | /** 13 | * @author guqing 14 | * @date 2020-06-03 15 | */ 16 | public interface RoleService extends IService { 17 | 18 | /** 19 | * 根据条件查询角色信息 20 | * @param roleQuery 查询条件 21 | * @return 返回分页角色列表 22 | */ 23 | Page listBy(RoleQuery roleQuery); 24 | 25 | /** 26 | * 创建或更新角色和角色关联的菜单信息 27 | * @param role 角色信息 28 | * @param authorities api scope names 29 | */ 30 | void createOrUpdate(Role role, Set authorities); 31 | 32 | /** 33 | * 根据角色id查询角色详情 34 | * @param roleId 角色id 35 | * @return 查询到返回角色详情否则返回{@code null} 36 | */ 37 | RoleDTO getRoleById(Long roleId); 38 | 39 | /** 40 | * 删除角色 41 | * @param roleId 角色id 42 | */ 43 | void deleteById(Long roleId); 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/service/UserConnectionService.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import me.zhyd.oauth.model.AuthUser; 5 | import xyz.guqing.creek.model.entity.UserConnection; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | *

11 | * 系统用户社交账户关联表 服务类 12 | *

13 | * 14 | * @author guqing 15 | * @since 2020-05-21 16 | */ 17 | public interface UserConnectionService extends IService { 18 | /** 19 | * 根据第三方登录识别码和用户uuid查询第三方帐号信息 20 | * @param source 第三方识别码 21 | * @param uuid 用户唯一标识 22 | * @return 如果查询返回数据,否则抛出NotFoundException 23 | */ 24 | UserConnection getBySourceAndUuid(String source, String uuid); 25 | 26 | /** 27 | * 创建第三方登录帐号 28 | * @param userId 用户id 29 | * @param authUser 第三方登录用户信息 30 | */ 31 | void create(Long userId, AuthUser authUser); 32 | 33 | /** 34 | * 根据用户名查询该用户绑定的所有第三方帐号 35 | * @param userId 用户id 36 | * @return 如果查询到返回第三方帐号集合,否则返回空集合 37 | */ 38 | List listByUserId(Long userId); 39 | 40 | /** 41 | * 根据用户id和第三方类型解绑帐号 42 | * @param userId 用户id 43 | * @param providerName 第三方认证类型 44 | */ 45 | void deleteBy(Long userId, String providerName); 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/service/UserGroupService.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import xyz.guqing.creek.model.dto.UserGroupTree; 5 | import xyz.guqing.creek.model.entity.UserGroup; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | *

11 | * 用户组表 服务类 12 | *

13 | * 14 | * @author guqing 15 | * @since 2020-05-21 16 | */ 17 | public interface UserGroupService extends IService { 18 | /** 19 | * 分页查询用户组列表 20 | * @param name 用户组名称,非必填 21 | * @return 返回用户组列表分组 22 | */ 23 | List listBy(String name); 24 | 25 | /** 26 | * 创建或更新用户组 27 | * @param userGroup 用户组参数 28 | */ 29 | void createOrUpdate(UserGroup userGroup); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/service/UserLoginLogService.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.service; 2 | 3 | import com.baomidou.mybatisplus.core.metadata.IPage; 4 | import com.baomidou.mybatisplus.extension.service.IService; 5 | import xyz.guqing.creek.model.entity.UserLoginLog; 6 | import xyz.guqing.creek.model.params.LoginLogParam; 7 | import xyz.guqing.creek.model.support.PageQuery; 8 | 9 | /** 10 | *

11 | * 登录日志表 服务类 12 | *

13 | * 14 | * @author guqing 15 | * @since 2020-05-21 16 | */ 17 | public interface UserLoginLogService extends IService { 18 | /** 19 | * 根据条件分页查询用户登录日志 20 | * @param loginLogParam 查询参数 21 | * @param pageQuery 分页参数 22 | * @return 返回分页查询结果 23 | */ 24 | IPage listBy(LoginLogParam loginLogParam, PageQuery pageQuery); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/service/impl/ApiResourceServiceImpl.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.service.impl; 2 | 3 | import com.baomidou.mybatisplus.core.toolkit.Wrappers; 4 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | import lombok.AllArgsConstructor; 8 | import org.springframework.stereotype.Service; 9 | import xyz.guqing.creek.mapper.ApiResourceMapper; 10 | import xyz.guqing.creek.mapper.ApiScopeMapper; 11 | import xyz.guqing.creek.model.dto.ApiResourceDTO; 12 | import xyz.guqing.creek.model.dto.ApiScopeDTO; 13 | import xyz.guqing.creek.model.entity.ApiResource; 14 | import xyz.guqing.creek.model.entity.ApiScope; 15 | import xyz.guqing.creek.service.ApiResourceService; 16 | 17 | /** 18 | * @author guqing 19 | * @since 2022-01-12 20 | */ 21 | @Service 22 | @AllArgsConstructor 23 | public class ApiResourceServiceImpl extends ServiceImpl 24 | implements ApiResourceService { 25 | 26 | private final ApiScopeMapper apiScopeMapper; 27 | 28 | @Override 29 | public List listWithScopes() { 30 | return list(Wrappers.lambdaQuery(ApiResource.class) 31 | .orderByAsc(ApiResource::getSortIndex)) 32 | .stream().map(apiResource -> { 33 | ApiResourceDTO resourceDTO = new ApiResourceDTO().convertFrom(apiResource); 34 | List scopes = listScopesByResourceId(apiResource.getId()); 35 | resourceDTO.setScopes(scopes); 36 | return resourceDTO; 37 | }) 38 | .collect(Collectors.toList()); 39 | } 40 | 41 | private List listScopesByResourceId(Long resourceId) { 42 | return apiScopeMapper.selectList(Wrappers.lambdaQuery(ApiScope.class) 43 | .eq(ApiScope::getResourceId, resourceId) 44 | .orderByAsc(ApiScope::getSortIndex)).stream() 45 | .map(scope -> (ApiScopeDTO) new ApiScopeDTO().convertFrom(scope)) 46 | .collect(Collectors.toList()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/service/impl/CredentialsServiceImpl.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.service.impl; 2 | 3 | import com.baomidou.mybatisplus.core.toolkit.Wrappers; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | import lombok.AllArgsConstructor; 7 | import org.springframework.stereotype.Service; 8 | import xyz.guqing.creek.mapper.CredentialsMapper; 9 | import xyz.guqing.creek.model.dto.CredentialsDTO; 10 | import xyz.guqing.creek.model.entity.Credentials; 11 | import xyz.guqing.creek.service.CredentialsService; 12 | 13 | /** 14 | * @author guqing 15 | * @since 2022-01-14 16 | */ 17 | @Service 18 | @AllArgsConstructor 19 | public class CredentialsServiceImpl implements CredentialsService { 20 | 21 | private final CredentialsMapper credentialsMapper; 22 | 23 | @Override 24 | public List listAll() { 25 | return credentialsMapper.selectList(Wrappers.lambdaQuery(Credentials.class) 26 | .orderByDesc(Credentials::getCreateTime)) 27 | .stream() 28 | .map(credentials -> (CredentialsDTO) new CredentialsDTO().convertFrom(credentials)) 29 | .collect(Collectors.toList()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/utils/DateUtils.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.utils; 2 | 3 | import java.time.LocalDateTime; 4 | import java.time.format.DateTimeFormatter; 5 | import java.util.Calendar; 6 | import java.util.Date; 7 | 8 | /** 9 | * @author guqing 10 | * @date 2020-08-19 11 | */ 12 | public class DateUtils { 13 | public static final String FULL_TIME_PATTERN = "yyyyMMddHHmmss"; 14 | 15 | public static final String FULL_TIME_SPLIT_PATTERN = "yyyy-MM-dd HH:mm:ss"; 16 | 17 | public static final String CST_TIME_PATTERN = "EEE MMM dd HH:mm:ss zzz yyyy"; 18 | 19 | /** 20 | * 根据传入的格式,格式化时间 21 | * 22 | * @param localDateTime LocalDateTime 23 | * @param format 格式 24 | * @return 格式化后的字符串 25 | */ 26 | public static String formatFullTime(LocalDateTime localDateTime, String format) { 27 | DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format); 28 | return localDateTime.format(dateTimeFormatter); 29 | } 30 | 31 | public static Date dateAfterSeconds(Date date, int seconds) { 32 | Calendar calendar = Calendar.getInstance(); 33 | calendar.setTime(new Date()); 34 | calendar.add(Calendar.SECOND, (int)seconds); 35 | return calendar.getTime(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/utils/PageUtils.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.utils; 2 | 3 | import com.baomidou.mybatisplus.core.metadata.OrderItem; 4 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 5 | import org.apache.commons.lang3.StringUtils; 6 | import xyz.guqing.creek.model.constant.CreekConstant; 7 | import xyz.guqing.creek.model.support.PageQuery; 8 | 9 | /** 10 | * mybatis plus 分页和排序工具类 11 | * @author guqing 12 | * @date 2020-09-01 13 | */ 14 | public class PageUtils { 15 | private PageUtils(){} 16 | 17 | public static Page convert(PageQuery pageQuery) { 18 | Page page = new Page<>(); 19 | 20 | String sortField = pageQuery.getField(); 21 | if(StringUtils.isNotBlank(sortField)) { 22 | OrderItem orderItem = new OrderItem(); 23 | orderItem.setAsc(CreekConstant.ORDER_ASC.equalsIgnoreCase(pageQuery.getOrder())); 24 | // 驼峰转下划线 25 | String underscoreField = CreekUtils.camelToUnderscore(sortField); 26 | orderItem.setColumn(underscoreField); 27 | page.addOrder(orderItem); 28 | } 29 | 30 | page.setCurrent(pageQuery.getCurrent()); 31 | page.setSize(pageQuery.getPageSize()); 32 | return page; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/xyz/guqing/creek/utils/SecurityUserHelper.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.utils; 2 | 3 | import java.util.Objects; 4 | import lombok.AccessLevel; 5 | import lombok.NoArgsConstructor; 6 | import org.springframework.security.core.Authentication; 7 | import org.springframework.security.core.context.SecurityContextHolder; 8 | 9 | /** 10 | * 用户信息工具类 11 | * 12 | * @author guqin 13 | * @date 2019-08-09 16:35 14 | */ 15 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 16 | public class SecurityUserHelper { 17 | 18 | /** 19 | * 获取当前用户 20 | * 21 | * @return 返回认证对象 22 | */ 23 | public static Authentication getCurrentUserAuthentication() { 24 | return SecurityContextHolder.getContext().getAuthentication(); 25 | } 26 | 27 | public static boolean isCurrentUser(String username) { 28 | return Objects.equals(getCurrentUsername(), username); 29 | } 30 | 31 | /** 32 | * 获取当前登录用户名 33 | * 34 | * @return 返回登录用户名 35 | */ 36 | public static String getCurrentUsername() { 37 | Authentication authentication = getCurrentUserAuthentication(); 38 | return authentication.getName(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/resources/app.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDOjnDY1K1lrOrK 3 | ETfKfDlVGVbPCiy+TDmTaXg4SWjdHUpXfqbXMkSX/j2dJ/ECqb/FtsvVxiSwRieG 4 | 3MWDKWlNRz0C0QKrsoDYbcvLf68uc7L5eKFZhu0AkXP4T5BIbdMXH8V0+5e+6R+n 5 | eHahFhMyaiYoHVrPMrW2Jn9iWIXuNTDpg9VFhejN4jG1wQqIu1puKeGYPQvtfNO5 6 | Ef5cQdEFCvFfuDQvNhLgI1f798qY6EVFfRo2S3LLCut3wfDzRZiUN4Kz8qYz42Zv 7 | 97GS1gW/lfcEsmBApov9xiIaUzUECN35XbZYMK5Y4gfhAseZ+tlj+YarEiPjAtL1 8 | JPUehCmRAgMBAAECggEAKmaI+ammsoFtbO9d4X3gkvxxmmx/RM0G4KC84ekH0qPp 9 | l85S10flVsIEydbiHWbVC/P7IbXb4Cd2g7OcA9GjYQ6nkoVvI+mvkz3uoKZkQofT 10 | jGxbyrHswroY8Tb76jJJK60E7n+a5cCbE9ihmW2boTSzAncMJg5FyM9cRMbhL0Vz 11 | h90/gE2U8awQ8Ug47BN1Dk/awxB9f5zVqI+LCGC0Py0/oQudjSaqPihydTsuqkhV 12 | xNu3NMcL/POt9WxmYyJFDJRW3+EYraPumdUsIWw8p4JJDt1jkyNpSbjGhu8vzRYX 13 | 0QSo1pa3VrDY4guEMk4RdJsKJDqQPTvCTTgDYBzFlQKBgQDq98CRLTwqHSEWyVKN 14 | 0KRujhVAVEmLDvPxZ2tVaMM37RanCHYSfHLiYCD54rUv7BFWjQ+hfq3iHUpgrefN 15 | KRS9e01mT0f24sAsWfhrFzrhlHaQStFgOw4uvwIDCfzrBeQQsqcAvWSjNr8CqSMX 16 | UIGz9oB6EP39PT3QxT3oYf3ItwKBgQDhC6WN78+0sf2zlptQ7V02eWaRfePtQfmb 17 | ow3c9aF8V7sSwDzjInqV5Bva4RyftYRTYZttBiANjGZ1pSNPi/2p7b+0hxJ1pPf8 18 | 6VcFDJBGLbFYNDWOux13KRJToMY0ckzSeBXgkWLVFSfESuoXzy+8bj5eMavJLg6L 19 | 2Ek6q6mH9wKBgBZmmE0+6sV5EXaCqwQqKAMCOLRxVLGVM1yIZ4s0+aeTSt2RyO/q 20 | PWmnkH1CR9PRxbVirWLQGPO9pyGgcsD0ca2+25otZMb8xyVzTmOnS03GQadv+pYa 21 | CzgZra9sfFhLr3qIDbPcWoPU7FDsnxPR8QufLJB2nkBOXl5Q753/+ZnxAoGBAI47 22 | GisWwaNmSv3R1d/T5PGk0Jprgj5VUDh5WS2pYKKBoA49yT2UcP2C6cfwNnMJ+dPp 23 | AJ5rHJ7zeV4pPKPtyig3xs2GALixxrnlj8X1Jsnz3v3sIV1QDVNedeK83ggPpVXv 24 | 54PC3z/k2vlIj6L0oyroUiqeIgBIR5FC5SVbkQ4JAoGBAOEGQkqw1xR3fd27J6/R 25 | s9hOhItPnjExf5yqeg0nbZYIGd+6PiaVBBWUefZDDS79KUwTiqiHGP7iEVghJr9C 26 | xJI9odzY8WQJ+Q9ZQy1VQfP5mkRUTTkABhykXfWsHckO7yP6c3kwNIOOki8QPrmY 27 | 3GKNb5HtQVpazCvrB5PFh65g 28 | -----END PRIVATE KEY----- -------------------------------------------------------------------------------- /src/main/resources/app.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzo5w2NStZazqyhE3ynw5 3 | VRlWzwosvkw5k2l4OElo3R1KV36m1zJEl/49nSfxAqm/xbbL1cYksEYnhtzFgylp 4 | TUc9AtECq7KA2G3Ly3+vLnOy+XihWYbtAJFz+E+QSG3TFx/FdPuXvukfp3h2oRYT 5 | MmomKB1azzK1tiZ/YliF7jUw6YPVRYXozeIxtcEKiLtabinhmD0L7XzTuRH+XEHR 6 | BQrxX7g0LzYS4CNX+/fKmOhFRX0aNktyywrrd8Hw80WYlDeCs/KmM+Nmb/exktYF 7 | v5X3BLJgQKaL/cYiGlM1BAjd+V22WDCuWOIH4QLHmfrZY/mGqxIj4wLS9ST1HoQp 8 | kQIDAQAB 9 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | spring: 4 | jackson: 5 | date-format: yyyy-MM-dd HH:mm:ss 6 | output: 7 | ansi: 8 | enabled: always 9 | devtools: 10 | restart: 11 | enabled: true 12 | log-condition-evaluation-delta: false 13 | datasource: 14 | type: com.zaxxer.hikari.HikariDataSource 15 | 16 | # H2 database configuration. 17 | driver-class-name: org.h2.Driver 18 | url: jdbc:h2:file:~/creek-dev/db/creek;AUTO_SERVER=TRUE 19 | username: admin 20 | password: 123456 21 | 22 | jpa: 23 | hibernate: 24 | ddl-auto: update 25 | open-in-view: false 26 | creek: 27 | security: 28 | oauth2: 29 | jwt: 30 | public-key-location: classpath:app.pub 31 | private-key-location: classpath:app.key 32 | logging: 33 | level: 34 | xyz.guqing.creek: DEBUG 35 | org.hibernate: INFO 36 | org.hibernate.type.descriptor.sql.BasicBinder: INFO 37 | org.hibernate.type.descriptor.sql.BasicExtractor: INFO 38 | -------------------------------------------------------------------------------- /src/main/resources/ip2region/ip2region.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/src/main/resources/ip2region/ip2region.db -------------------------------------------------------------------------------- /src/main/resources/static/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/src/main/resources/static/avatar.png -------------------------------------------------------------------------------- /src/main/resources/static/css/chunk-20317508.e966bac8.css: -------------------------------------------------------------------------------- 1 | .avatar-upload-preview[data-v-4790c0d0]{position:absolute;top:50%;-webkit-transform:translate(50%,-50%);transform:translate(50%,-50%);width:180px;height:180px;border-radius:50%;-webkit-box-shadow:0 0 4px #ccc;box-shadow:0 0 4px #ccc;overflow:hidden}.avatar-upload-preview img[data-v-4790c0d0]{width:100%;height:100%}.page-header-wrapper-grid-content-main[data-v-1aa4268f]{width:100%;height:100%;min-height:100%;-webkit-transition:.3s;transition:.3s}.page-header-wrapper-grid-content-main .account-center-avatarHolder[data-v-1aa4268f]{text-align:center;margin-bottom:24px}.page-header-wrapper-grid-content-main .account-center-avatarHolder>.avatar[data-v-1aa4268f]{margin:0 auto;width:104px;height:104px;margin-bottom:20px;border-radius:50%;overflow:hidden}.page-header-wrapper-grid-content-main .account-center-avatarHolder>.avatar img[data-v-1aa4268f]{height:100%;width:100%}.page-header-wrapper-grid-content-main .account-center-avatarHolder .username[data-v-1aa4268f]{color:rgba(0,0,0,.85);font-size:20px;line-height:28px;font-weight:500;margin-bottom:4px}.page-header-wrapper-grid-content-main .account-center-detail p[data-v-1aa4268f]{margin-bottom:8px;padding-left:26px;position:relative}.page-header-wrapper-grid-content-main .account-center-detail i[data-v-1aa4268f]{position:absolute;height:14px;width:14px;left:0;top:4px}.page-header-wrapper-grid-content-main .account-center-tags .ant-tag[data-v-1aa4268f]{margin-bottom:8px}.page-header-wrapper-grid-content-main .tagsTitle[data-v-1aa4268f],.page-header-wrapper-grid-content-main .teamTitle[data-v-1aa4268f]{font-weight:500;color:rgba(0,0,0,.85);margin-bottom:12px}.page-header-wrapper-grid-content-main .avatar[data-v-1aa4268f]{border:1px solid #ccc}.page-header-wrapper-grid-content-main .avatar-preview[data-v-1aa4268f]{width:100%;height:100%} -------------------------------------------------------------------------------- /src/main/resources/static/css/chunk-2068754c.1af36cb9.css: -------------------------------------------------------------------------------- 1 | .search[data-v-19c36813]{margin-bottom:54px}.fold[data-v-19c36813]{width:calc(100% - 216px);display:inline-block}.operator[data-v-19c36813]{margin-bottom:18px}@media screen and (max-width:900px){.fold[data-v-19c36813]{width:100%}} -------------------------------------------------------------------------------- /src/main/resources/static/css/chunk-2be72548.42caeaa2.css: -------------------------------------------------------------------------------- 1 | .card[data-v-5c3e7c89]{margin-bottom:24px}.popover-wrapper[data-v-5c3e7c89] .antd-pro-pages-forms-style-errorPopover .ant-popover-inner-content{min-width:256px;max-height:290px;padding:0;overflow:auto}.antd-pro-pages-forms-style-errorIcon[data-v-5c3e7c89]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;margin-right:24px;color:#f5222d;cursor:pointer}.antd-pro-pages-forms-style-errorIcon i[data-v-5c3e7c89]{margin-right:4px}.antd-pro-pages-forms-style-errorListItem[data-v-5c3e7c89]{padding:8px 16px;list-style:none;border-bottom:1px solid #e8e8e8;cursor:pointer;-webkit-transition:all .3s;transition:all .3s}.antd-pro-pages-forms-style-errorListItem[data-v-5c3e7c89]:hover{background:#e6f7ff}.antd-pro-pages-forms-style-errorListItem .antd-pro-pages-forms-style-errorIcon[data-v-5c3e7c89]{float:left;margin-top:4px;margin-right:12px;padding-bottom:22px;color:#f5222d}.antd-pro-pages-forms-style-errorListItem .antd-pro-pages-forms-style-errorField[data-v-5c3e7c89]{margin-top:2px;color:rgba(0,0,0,.45);font-size:12px} -------------------------------------------------------------------------------- /src/main/resources/static/css/chunk-2e3134d4.c59efe83.css: -------------------------------------------------------------------------------- 1 | .user-register.error{color:red}.user-register.warning{color:#ff7e05}.user-register.success{color:#52c41a}.user-layout-register .ant-input-group-addon:first-child{background-color:#fff}.user-layout-register>h3[data-v-71fb5786]{font-size:16px;margin-bottom:20px}.user-layout-register .getCaptcha[data-v-71fb5786]{display:block;width:100%;height:40px}.user-layout-register .register-button[data-v-71fb5786]{width:50%}.user-layout-register .login[data-v-71fb5786]{float:right;line-height:40px} -------------------------------------------------------------------------------- /src/main/resources/static/css/chunk-5c2da618.b6b81657.css: -------------------------------------------------------------------------------- 1 | .extra-wrapper[data-v-6ebfe19c]{line-height:55px;padding-right:24px}.extra-wrapper .extra-item[data-v-6ebfe19c]{display:inline-block;margin-right:24px}.extra-wrapper .extra-item a[data-v-6ebfe19c]{margin-left:24px}.antd-pro-pages-dashboard-analysis-twoColLayout[data-v-6ebfe19c]{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;display:block;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap}.antd-pro-pages-dashboard-analysis-salesCard[data-v-6ebfe19c]{height:calc(100% - 24px)}.antd-pro-pages-dashboard-analysis-salesCard[data-v-6ebfe19c] .ant-card-head{position:relative}.dashboard-analysis-iconGroup i[data-v-6ebfe19c]{margin-left:16px;color:rgba(0,0,0,.45);cursor:pointer;-webkit-transition:color .32s;transition:color .32s;color:#000}.analysis-salesTypeRadio[data-v-6ebfe19c]{position:absolute;right:54px;bottom:12px} -------------------------------------------------------------------------------- /src/main/resources/static/css/chunk-60c3c97d.9642a1cc.css: -------------------------------------------------------------------------------- 1 | .user-layout-login label[data-v-6396b0d1]{font-size:14px}.user-layout-login .getCaptcha[data-v-6396b0d1]{display:block;width:100%;height:40px}.user-layout-login .forge-password[data-v-6396b0d1]{font-size:14px}.user-layout-login button.login-button[data-v-6396b0d1]{padding:0 15px;font-size:16px;height:40px;width:100%}.user-layout-login .user-login-other[data-v-6396b0d1]{text-align:left;margin-top:24px;line-height:22px}.user-layout-login .user-login-other .item-icon[data-v-6396b0d1]{font-size:24px;color:rgba(0,0,0,.2);margin-left:16px;vertical-align:middle;cursor:pointer;-webkit-transition:color .3s;transition:color .3s}.user-layout-login .user-login-other .item-icon[data-v-6396b0d1]:hover{color:#1890ff}.user-layout-login .user-login-other .register[data-v-6396b0d1]{float:right} -------------------------------------------------------------------------------- /src/main/resources/static/css/chunk-ac0c6ae6.78a6d452.css: -------------------------------------------------------------------------------- 1 | .numeric-input .ant-tooltip-inner{min-width:32px;min-height:37px}.numeric-input .numeric-input-title{font-size:14px} -------------------------------------------------------------------------------- /src/main/resources/static/css/chunk-c53a1472.10aa8baa.css: -------------------------------------------------------------------------------- 1 | .step-form-style-desc[data-v-c4df8d6e]{padding:0 56px;color:rgba(0,0,0,.45)}.step-form-style-desc h3[data-v-c4df8d6e]{margin:0 0 12px;color:rgba(0,0,0,.45);font-size:16px;line-height:32px}.step-form-style-desc h4[data-v-c4df8d6e]{margin:0 0 4px;color:rgba(0,0,0,.45);font-size:14px;line-height:22px}.step-form-style-desc p[data-v-c4df8d6e]{margin-top:0;margin-bottom:12px;line-height:22px}.stepFormText[data-v-563ba83e]{margin-bottom:24px}.information[data-v-3c171f5b],.stepFormText .ant-form-item-control[data-v-563ba83e],.stepFormText .ant-form-item-label[data-v-563ba83e]{line-height:22px}.information .ant-row[data-v-3c171f5b]:not(:last-child){margin-bottom:24px}.money[data-v-3c171f5b]{font-family:Helvetica Neue,sans-serif;font-weight:500;font-size:20px;line-height:14px}.steps[data-v-a879d9f8]{max-width:750px;margin:16px auto} -------------------------------------------------------------------------------- /src/main/resources/static/icon/alipay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/src/main/resources/static/icon/alipay.png -------------------------------------------------------------------------------- /src/main/resources/static/icon/dingtalk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/src/main/resources/static/icon/dingtalk.png -------------------------------------------------------------------------------- /src/main/resources/static/icon/gitee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/src/main/resources/static/icon/gitee.png -------------------------------------------------------------------------------- /src/main/resources/static/icon/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/src/main/resources/static/icon/github.png -------------------------------------------------------------------------------- /src/main/resources/static/icon/microsoft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/src/main/resources/static/icon/microsoft.png -------------------------------------------------------------------------------- /src/main/resources/static/icon/qq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/src/main/resources/static/icon/qq.png -------------------------------------------------------------------------------- /src/main/resources/static/icon/taobao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/src/main/resources/static/icon/taobao.png -------------------------------------------------------------------------------- /src/main/resources/static/icon/tencent_cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/src/main/resources/static/icon/tencent_cloud.png -------------------------------------------------------------------------------- /src/main/resources/static/icon/weibo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/src/main/resources/static/icon/weibo.png -------------------------------------------------------------------------------- /src/main/resources/static/icon/weixin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guqing/creek/76e813bdf570a63ba6e435058cf12f79a0eb6680/src/main/resources/static/icon/weixin.png -------------------------------------------------------------------------------- /src/main/resources/static/js/chunk-2d0aa1b9.9b738bd3.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0aa1b9"],{1037:function(t,e,n){"use strict";n.r(e);var r=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("a-result",{attrs:{isSuccess:!0,content:!1,title:t.email,"sub-title":t.description},scopedSlots:t._u([{key:"extra",fn:function(){return[n("a-button",{attrs:{size:"large",type:"primary"}},[t._v("查看邮箱")]),n("a-button",{staticStyle:{"margin-left":"8px"},attrs:{size:"large"},on:{click:t.goHomeHandle}},[t._v("返回首页")])]},proxy:!0}])})},a=[],o={name:"RegisterResult",data:function(){return{description:"激活邮件已发送到你的邮箱中,邮件有效期为24小时。请及时登录邮箱,点击邮件中的链接激活帐户。",form:{}}},computed:{email:function(){var t=this.form&&this.form.email||"xxx";return"你的账户:".concat(t," 注册成功")}},created:function(){this.form=this.$route.params},methods:{goHomeHandle:function(){this.$router.push({name:"login"})}}},i=o,s=n("2877"),c=Object(s["a"])(i,r,a,!1,null,"4a6c53ae",null);e["default"]=c.exports}}]); -------------------------------------------------------------------------------- /src/main/resources/static/js/chunk-2d221c57.e35dd895.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d221c57"],{cc89:function(t,e,o){"use strict";o.r(e);var n=function(){var t=this,e=t.$createElement,o=t._self._c||e;return o("a-result",{attrs:{status:"404",title:"404","sub-title":"Sorry, the page you visited does not exist."},scopedSlots:t._u([{key:"extra",fn:function(){return[o("a-button",{attrs:{type:"primary"},on:{click:t.toHome}},[t._v(" Back Home ")])]},proxy:!0}])})},s=[],r={name:"Exception404",methods:{toHome:function(){this.$router.push({path:"/"})}}},u=r,c=o("2877"),a=Object(c["a"])(u,n,s,!1,null,null,null);e["default"]=a.exports}}]); -------------------------------------------------------------------------------- /src/main/resources/static/js/chunk-70c7a28c.1488c580.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-70c7a28c"],{2432:function(t,e,a){},"5a70":function(t,e,a){"use strict";var i=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("div",{class:t.prefixCls,style:{width:t.barWidth,transition:"0.3s all"}},[a("div",{staticStyle:{float:"left"}},[t._t("extra",(function(){return[t._v(t._s(t.extra))]}))],2),a("div",{staticStyle:{float:"right"}},[t._t("default")],2)])},o=[],l=(a("a9e3"),{name:"FooterToolBar",props:{prefixCls:{type:String,default:"ant-pro-footer-toolbar"},collapsed:{type:Boolean,default:!1},isMobile:{type:Boolean,default:!1},siderWidth:{type:Number,default:void 0},extra:{type:[String,Object],default:""}},computed:{barWidth:function(){return this.isMobile?void 0:"calc(100% - ".concat(this.collapsed?80:this.siderWidth||256,"px)")}}}),r=l,n=a("2877"),s=Object(n["a"])(r,i,o,!1,null,"5028374f",null),c=s.exports;a("2432"),e["a"]=c}}]); -------------------------------------------------------------------------------- /src/main/resources/static/js/lang-zh-CN.8cf88fd4.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["lang-zh-CN"],{2807:function(e,a,o){"use strict";o.r(a);var t=o("5530"),n=o("3579"),l=o("41b2"),r=o.n(l),c={today:"今天",now:"此刻",backToToday:"返回今天",ok:"确定",timeSelect:"选择时间",dateSelect:"选择日期",weekSelect:"选择周",clear:"清除",month:"月",year:"年",previousMonth:"上个月 (翻页上键)",nextMonth:"下个月 (翻页下键)",monthSelect:"选择月份",yearSelect:"选择年份",decadeSelect:"选择年代",yearFormat:"YYYY年",dayFormat:"D日",dateFormat:"YYYY年M月D日",dateTimeFormat:"YYYY年M月D日 HH时mm分ss秒",previousYear:"上一年 (Control键加左方向键)",nextYear:"下一年 (Control键加右方向键)",previousDecade:"上一年代",nextDecade:"下一年代",previousCentury:"上一世纪",nextCentury:"下一世纪"},i={placeholder:"请选择时间"},d=i,m={lang:r()({placeholder:"请选择日期",rangePlaceholder:["开始日期","结束日期"]},c),timePickerLocale:r()({},d)};m.lang.ok="确 定";var s=m,p=s,h={"btn:save":"保存","btn:cancel":"取消","btn:clear":"清除"},u={locale:"zh-cn",Pagination:n["a"],DatePicker:s,TimePicker:d,Calendar:p,ColorPicker:h,global:{placeholder:"请选择"},Table:{filterTitle:"筛选",filterConfirm:"确定",filterReset:"重置",selectAll:"全选当页",selectInvert:"反选当页",sortTitle:"排序",expand:"展开行",collapse:"关闭行"},Modal:{okText:"确定",cancelText:"取消",justOkText:"知道了"},Popconfirm:{cancelText:"取消",okText:"确定"},Transfer:{searchPlaceholder:"请输入搜索内容",itemUnit:"项",itemsUnit:"项"},Upload:{uploading:"文件上传中",removeFile:"删除文件",uploadError:"上传错误",previewFile:"预览文件",downloadFile:"下载文件"},Empty:{description:"暂无数据"},Icon:{icon:"图标"},Text:{edit:"编辑",copy:"复制",copied:"复制成功",expand:"展开"},PageHeader:{back:"返回"}},b=u,k=o("5c3a"),T=o.n(k),Y={antLocale:b,momentName:"zh-cn",momentLocale:T.a},x={message:"-","menu.home":"主页","menu.dashboard":"仪表盘","menu.dashboard.analysis":"分析页","menu.dashboard.monitor":"监控页","menu.dashboard.workplace":"工作台"};a["default"]=Object(t["a"])(Object(t["a"])({},Y),x)}}]); -------------------------------------------------------------------------------- /src/main/resources/static/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/templates/error.ftl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 第三方登录失败 9 | 10 | 17 | 18 | ${error} 19 | 20 | -------------------------------------------------------------------------------- /src/main/resources/templates/socialLoginResult.ftl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 登录跳转中 9 | 10 | 11 | 登录中.. 12 | 20 | 21 | -------------------------------------------------------------------------------- /src/test/java/xyz/guqing/creek/CreekApplicationTest.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | /** 7 | * @author guqing 8 | * @date 2020-10-22 9 | */ 10 | @SpringBootTest 11 | class CreekApplicationTest { 12 | @Test 13 | void test() { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/xyz/guqing/creek/identity/apitoken/PersonalAccessTokenUtilsTest.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.apitoken; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import javax.crypto.SecretKey; 6 | import org.junit.jupiter.api.Test; 7 | 8 | class PersonalAccessTokenUtilsTest { 9 | 10 | @Test 11 | void generate() { 12 | SecretKey secretKey = PersonalAccessTokenUtils.generateSecretKey(); 13 | 14 | for (int i = 0; i < 1000000; i++) { 15 | String personalAccessToken = 16 | PersonalAccessTokenUtils.generate(PersonalAccessTokenType.ADMIN_TOKEN, secretKey); 17 | boolean b = PersonalAccessTokenUtils.verifyChecksum(personalAccessToken, secretKey); 18 | assertThat(b).isTrue(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/xyz/guqing/creek/identity/authentication/verifyer/BearerTokenAuthenticationTokenTest.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authentication.verifyer; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; 5 | 6 | import org.junit.jupiter.api.Test; 7 | import xyz.guqing.creek.identity.authentication.verifier.BearerTokenAuthenticationToken; 8 | 9 | /** 10 | * Tests for {@link BearerTokenAuthenticationToken} 11 | * 12 | * @author guqing 13 | * @since 2.0.0 14 | */ 15 | public class BearerTokenAuthenticationTokenTest { 16 | @Test 17 | public void constructorWhenTokenIsNullThenThrowsException() { 18 | assertThatIllegalArgumentException() 19 | .isThrownBy(() -> new BearerTokenAuthenticationToken(null)) 20 | .withMessageContaining("token cannot be empty"); 21 | } 22 | 23 | @Test 24 | public void constructorWhenTokenIsEmptyThenThrowsException() { 25 | assertThatIllegalArgumentException() 26 | .isThrownBy(() -> new BearerTokenAuthenticationToken("")) 27 | .withMessageContaining("token cannot be empty"); 28 | } 29 | 30 | @Test 31 | public void constructorWhenTokenHasValueThenConstructedCorrectly() { 32 | BearerTokenAuthenticationToken token = new BearerTokenAuthenticationToken("token"); 33 | assertThat(token.getToken()).isEqualTo("token"); 34 | assertThat(token.getPrincipal()).isEqualTo("token"); 35 | assertThat(token.getCredentials()).isEqualTo("token"); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/xyz/guqing/creek/identity/authentication/verifyer/TestJwts.java: -------------------------------------------------------------------------------- 1 | package xyz.guqing.creek.identity.authentication.verifyer; 2 | 3 | import java.time.Instant; 4 | import java.util.List; 5 | import org.springframework.security.oauth2.jwt.Jwt; 6 | 7 | /** 8 | * @author guqing 9 | * @since 2.0.0 10 | */ 11 | public final class TestJwts { 12 | 13 | private TestJwts() { 14 | } 15 | 16 | public static Jwt.Builder jwt() { 17 | return Jwt.withTokenValue("token") 18 | .header("alg", "none") 19 | .audience(List.of("https://audience.example.org")) 20 | .expiresAt(Instant.MAX) 21 | .issuedAt(Instant.MIN) 22 | .issuer("https://issuer.example.org") 23 | .jti("jti") 24 | .notBefore(Instant.MIN) 25 | .subject("mock-test-subject"); 26 | } 27 | 28 | public static Jwt user() { 29 | return jwt() 30 | .claim("sub", "mock-test-subject") 31 | .build(); 32 | } 33 | } 34 | --------------------------------------------------------------------------------