diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..667aaef
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/dolphin-commons/dolphin-common-core/pom.xml b/dolphin-commons/dolphin-common-core/pom.xml
new file mode 100644
index 0000000..df142dc
--- /dev/null
+++ b/dolphin-commons/dolphin-common-core/pom.xml
@@ -0,0 +1,42 @@
+
+
+ 4.0.0
+
+ day.gitlab
+ dolphin-backend
+ 0.0.1-SNAPSHOT
+
+
+ dolphin-common-core
+ jar
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
diff --git a/dolphin-commons/dolphin-common-core/src/main/java/day/gitlab/dolphin/common/core/constants/Constants.java b/dolphin-commons/dolphin-common-core/src/main/java/day/gitlab/dolphin/common/core/constants/Constants.java
new file mode 100644
index 0000000..cce7b0a
--- /dev/null
+++ b/dolphin-commons/dolphin-common-core/src/main/java/day/gitlab/dolphin/common/core/constants/Constants.java
@@ -0,0 +1,8 @@
+package day.gitlab.dolphin.common.core.constants;
+
+public class Constants {
+
+ public static final String SUCCESS = "success";
+
+ public static final String FAILURE = "failure";
+}
diff --git a/dolphin-commons/dolphin-common-core/src/main/java/day/gitlab/dolphin/common/core/entity/Result.java b/dolphin-commons/dolphin-common-core/src/main/java/day/gitlab/dolphin/common/core/entity/Result.java
new file mode 100644
index 0000000..e357c32
--- /dev/null
+++ b/dolphin-commons/dolphin-common-core/src/main/java/day/gitlab/dolphin/common/core/entity/Result.java
@@ -0,0 +1,55 @@
+package day.gitlab.dolphin.common.core.entity;
+
+import day.gitlab.dolphin.common.core.exception.BusinessException;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.function.Supplier;
+
+import static day.gitlab.dolphin.common.core.constants.Constants.FAILURE;
+import static day.gitlab.dolphin.common.core.constants.Constants.SUCCESS;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class Result {
+
+ private int code;
+
+ private String message;
+
+ private Object data;
+
+ public static Result success() {
+ return Result.builder().code(200).message(SUCCESS).build();
+ }
+
+ public static Result success(Object data) {
+ Result result = Result.builder().code(200).message(SUCCESS).build();
+ if (data instanceof Supplier) {
+ result.setData(((Supplier>) data).get());
+ } else {
+ result.setData(data);
+ }
+ return result;
+ }
+
+ public static Result failure() {
+ return Result.builder().code(500).message(FAILURE).build();
+ }
+
+ public static Result failure(String message) {
+ return Result.builder().code(500).message(message).build();
+ }
+
+ public static Result failure(int code, String message) {
+ return Result.builder().code(code).message(message).build();
+ }
+
+ public static Result failure(BusinessException businessException) {
+ return Result.builder().code(businessException.getCode()).message(businessException.getMessage()).build();
+ }
+}
diff --git a/dolphin-commons/dolphin-common-core/src/main/java/day/gitlab/dolphin/common/core/exception/BusinessException.java b/dolphin-commons/dolphin-common-core/src/main/java/day/gitlab/dolphin/common/core/exception/BusinessException.java
new file mode 100644
index 0000000..789c419
--- /dev/null
+++ b/dolphin-commons/dolphin-common-core/src/main/java/day/gitlab/dolphin/common/core/exception/BusinessException.java
@@ -0,0 +1,14 @@
+package day.gitlab.dolphin.common.core.exception;
+
+import lombok.Getter;
+
+@Getter
+public class BusinessException extends RuntimeException {
+
+ private final int code;
+
+ public BusinessException(int code, String message) {
+ super(message);
+ this.code = code;
+ }
+}
diff --git a/dolphin-commons/dolphin-common-core/src/main/java/day/gitlab/dolphin/common/core/exception/GlobalExceptionAdvice.java b/dolphin-commons/dolphin-common-core/src/main/java/day/gitlab/dolphin/common/core/exception/GlobalExceptionAdvice.java
new file mode 100644
index 0000000..1a5e3e6
--- /dev/null
+++ b/dolphin-commons/dolphin-common-core/src/main/java/day/gitlab/dolphin/common/core/exception/GlobalExceptionAdvice.java
@@ -0,0 +1,21 @@
+package day.gitlab.dolphin.common.core.exception;
+
+import day.gitlab.dolphin.common.core.entity.Result;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+
+@Component
+@ControllerAdvice
+public class GlobalExceptionAdvice {
+
+ @ExceptionHandler(value = BusinessException.class)
+ public Result handleBusinessException(BusinessException e) {
+ return Result.failure(e);
+ }
+
+ @ExceptionHandler(value = Exception.class)
+ public Result handleException(Exception e) {
+ return Result.failure(e.getMessage());
+ }
+}
diff --git a/dolphin-commons/dolphin-common-security/pom.xml b/dolphin-commons/dolphin-common-security/pom.xml
new file mode 100644
index 0000000..dad3a22
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/pom.xml
@@ -0,0 +1,59 @@
+
+
+ 4.0.0
+
+ day.gitlab
+ dolphin-backend
+ 0.0.1-SNAPSHOT
+
+
+ dolphin-common-security
+ jar
+
+
+
+ day.gitlab
+ dolphin-common-core
+ ${project.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+ io.jsonwebtoken
+ jjwt-api
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/Authentication.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/Authentication.java
new file mode 100644
index 0000000..1806255
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/Authentication.java
@@ -0,0 +1,36 @@
+package day.gitlab.dolphin.common.security;
+
+import lombok.Getter;
+
+import java.util.List;
+
+@Getter
+public class Authentication {
+
+ private final UserPrincipal userPrincipal;
+
+ private final List userAuthorities;
+
+ public Authentication(UserPrincipal userPrincipal, List userAuthorities) {
+ this.userPrincipal = userPrincipal;
+ this.userAuthorities = userAuthorities;
+ }
+
+ public boolean hasAllAuthorities(String[] userAuthorities) {
+ for (String userAuthority : userAuthorities) {
+ if (!this.userAuthorities.contains(userAuthority)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean hasAnyAuthorities(String[] userAuthorities) {
+ for (String userAuthority : userAuthorities) {
+ if (this.userAuthorities.contains(userAuthority)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/AuthenticationFilter.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/AuthenticationFilter.java
new file mode 100644
index 0000000..5f67a8b
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/AuthenticationFilter.java
@@ -0,0 +1,58 @@
+package day.gitlab.dolphin.common.security;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import day.gitlab.dolphin.common.core.entity.Result;
+import day.gitlab.dolphin.common.core.exception.BusinessException;
+import day.gitlab.dolphin.common.security.annotation.AuthorityIgnoreInitializer;
+import day.gitlab.dolphin.common.security.config.SecurityConfig;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.http.MediaType;
+import org.springframework.lang.NonNull;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+
+@Component
+public class AuthenticationFilter extends OncePerRequestFilter {
+
+ private final SecurityConfig securityConfig;
+
+ private final AuthorityIgnoreInitializer authorityIgnoreInitializer;
+
+ private final AuthenticationInitialize authenticationInitialize;
+
+ public AuthenticationFilter(SecurityConfig securityConfig,
+ AuthorityIgnoreInitializer authorityIgnoreInitializer,
+ AuthenticationInitialize authenticationInitialize) {
+ this.securityConfig = securityConfig;
+ this.authorityIgnoreInitializer = authorityIgnoreInitializer;
+ this.authenticationInitialize = authenticationInitialize;
+ }
+
+ @Override
+ protected void doFilterInternal(@NonNull HttpServletRequest request,
+ @NonNull HttpServletResponse response,
+ @NonNull FilterChain filterChain) throws ServletException, IOException {
+ // 在未启用或是忽略校验的地址时直接放行
+ if (!securityConfig.isEnabled() || authorityIgnoreInitializer.isIgnoreUrl(request)) {
+ filterChain.doFilter(request, response);
+ }
+
+ try {
+ Authentication initialize = authenticationInitialize.initialize(request);
+ SecurityContextHolder.setAuthentication(initialize);
+ filterChain.doFilter(request, response);
+ } catch (BusinessException e) {
+ response.setStatus(e.getCode());
+ response.setContentType(MediaType.APPLICATION_JSON_VALUE);
+ response.setCharacterEncoding("UTF-8");
+ response.getWriter().write(new ObjectMapper().writeValueAsString(Result.failure(e)));
+ } finally {
+ SecurityContextHolder.clearAuthentication();
+ }
+ }
+}
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/AuthenticationInitialize.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/AuthenticationInitialize.java
new file mode 100644
index 0000000..1e68fcb
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/AuthenticationInitialize.java
@@ -0,0 +1,8 @@
+package day.gitlab.dolphin.common.security;
+
+import jakarta.servlet.http.HttpServletRequest;
+
+public interface AuthenticationInitialize {
+
+ Authentication initialize(HttpServletRequest request);
+}
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/AuthenticationProvider.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/AuthenticationProvider.java
new file mode 100644
index 0000000..3a10bb4
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/AuthenticationProvider.java
@@ -0,0 +1,10 @@
+package day.gitlab.dolphin.common.security;
+
+import java.util.List;
+
+public interface AuthenticationProvider {
+
+ UserPrincipal getUserPrincipal(String userId);
+
+ List getUserAuthorities(String userId);
+}
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/SecurityContextHolder.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/SecurityContextHolder.java
new file mode 100644
index 0000000..f77fb70
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/SecurityContextHolder.java
@@ -0,0 +1,20 @@
+package day.gitlab.dolphin.common.security;
+
+public class SecurityContextHolder {
+
+ private static final ThreadLocal CONTEXT = new ThreadLocal<>();
+
+ private SecurityContextHolder() {}
+
+ public static Authentication getAuthentication() {
+ return CONTEXT.get();
+ }
+
+ public static void setAuthentication(Authentication authentication) {
+ CONTEXT.set(authentication);
+ }
+
+ public static void clearAuthentication() {
+ CONTEXT.remove();
+ }
+}
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/UserPrincipal.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/UserPrincipal.java
new file mode 100644
index 0000000..fc32a06
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/UserPrincipal.java
@@ -0,0 +1,19 @@
+package day.gitlab.dolphin.common.security;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class UserPrincipal {
+
+ private String id;
+
+ private String username;
+
+ private String nickname;
+}
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/annotation/AuthorityCheck.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/annotation/AuthorityCheck.java
new file mode 100644
index 0000000..7e07367
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/annotation/AuthorityCheck.java
@@ -0,0 +1,18 @@
+package day.gitlab.dolphin.common.security.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 使用该注解注解的类会进行权限校验。
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AuthorityCheck {
+
+ AuthorityType type() default AuthorityType.AND;
+
+ String[] value();
+}
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/annotation/AuthorityCheckAspect.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/annotation/AuthorityCheckAspect.java
new file mode 100644
index 0000000..7357b5e
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/annotation/AuthorityCheckAspect.java
@@ -0,0 +1,32 @@
+package day.gitlab.dolphin.common.security.annotation;
+
+import day.gitlab.dolphin.common.security.Authentication;
+import day.gitlab.dolphin.common.security.SecurityContextHolder;
+import day.gitlab.dolphin.common.security.exception.NotAuthorityException;
+import day.gitlab.dolphin.common.security.exception.NotLoginException;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+
+@Aspect
+public class AuthorityCheckAspect {
+
+ @Before("@annotation(authorityCheck)")
+ public void check(JoinPoint joinPoint, AuthorityCheck authorityCheck) {
+ Authentication authentication = SecurityContextHolder.getAuthentication();
+ if (authentication == null) {
+ throw new NotLoginException();
+ }
+
+ // AuthorityCheck的type如果是AND,输出1
+ if (authorityCheck.type() == AuthorityType.AND) {
+ if (!authentication.hasAllAuthorities(authorityCheck.value())) {
+ throw new NotAuthorityException(authorityCheck.value());
+ }
+ } else if (authorityCheck.type() == AuthorityType.OR) {
+ if (!authentication.hasAnyAuthorities(authorityCheck.value())) {
+ throw new NotAuthorityException(authorityCheck.value());
+ }
+ }
+ }
+}
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/annotation/AuthorityIgnore.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/annotation/AuthorityIgnore.java
new file mode 100644
index 0000000..acf9c9b
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/annotation/AuthorityIgnore.java
@@ -0,0 +1,14 @@
+package day.gitlab.dolphin.common.security.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 使用该注解注解的类或方法会忽略校验
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AuthorityIgnore {
+}
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/annotation/AuthorityIgnoreInitializer.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/annotation/AuthorityIgnoreInitializer.java
new file mode 100644
index 0000000..3936a74
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/annotation/AuthorityIgnoreInitializer.java
@@ -0,0 +1,101 @@
+package day.gitlab.dolphin.common.security.annotation;
+
+import day.gitlab.dolphin.common.security.config.SecurityConfig;
+import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.lang.NonNull;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Component
+public class AuthorityIgnoreInitializer implements ApplicationContextAware {
+
+ private final List ignoreUrls = new ArrayList<>();
+
+ private SecurityConfig securityConfig;
+
+ @Override
+ public void setApplicationContext(@NonNull ApplicationContext ctx) throws BeansException {
+ String contextPath = ctx.getEnvironment().getProperty("server.servlet.context-path");
+ RequestMappingHandlerMapping requestMappingHandlerMapping = ctx.getBean(RequestMappingHandlerMapping.class);
+ Map handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
+
+ if (StringUtils.hasText(securityConfig.getIgnoreUrls())) {
+ Arrays.stream(securityConfig.getIgnoreUrls().split(","))
+ .filter(StringUtils::hasText)
+ .map(s -> {
+ String prefixUrl = StringUtils.hasLength(contextPath) ? contextPath : "";
+ prefixUrl = prefixUrl.endsWith("/") ? prefixUrl.substring(0, prefixUrl.length() - 1) : prefixUrl;
+ return s.startsWith("/") ? prefixUrl + s : prefixUrl + "/" + s;
+ })
+ .map(IgnoreUrl::new)
+ .forEach(url -> this.ignoreUrls.add(url));
+ }
+
+ for (RequestMappingInfo mappingInfo : handlerMethods.keySet()) {
+ HandlerMethod handlerMethod = handlerMethods.get(mappingInfo);
+ Class> beanClass = handlerMethod.getBeanType();
+
+ RequestMapping requestMapping = handlerMethod.getMethodAnnotation(RequestMapping.class);
+ if (requestMapping == null) {
+ continue;
+ }
+ AuthorityIgnore authorityIgnore = handlerMethod.getMethodAnnotation(AuthorityIgnore.class);
+ if (authorityIgnore == null && !beanClass.isAnnotationPresent(AuthorityIgnore.class)) {
+ continue;
+ }
+
+ System.out.println("beanClass:" + beanClass.getCanonicalName());
+ System.out.println("method:" + handlerMethod.getMethod().getName() + " -> " + mappingInfo.getPatternValues());
+
+ List urlPrefix = Arrays.stream(requestMapping.method())
+ .map(RequestMethod::name)
+ .map(StringBuffer::new)
+ .map(sb -> sb.append(":"))
+ .map(sb -> StringUtils.hasText(contextPath) ? sb.append(contextPath) : sb)
+ .map(StringBuffer::toString)
+ .map(sb -> sb.endsWith("/") ? sb.substring(0, sb.length() - 1) : sb)
+ .collect(Collectors.toList());
+ if (urlPrefix.isEmpty()) {
+ String prefixUrl = StringUtils.hasText(contextPath) ? contextPath : "/";
+ if (prefixUrl.endsWith("/")) {
+ prefixUrl = prefixUrl.substring(0, prefixUrl.length() - 1);
+ }
+ urlPrefix.add(prefixUrl);
+ }
+
+ urlPrefix.stream()
+ .flatMap(sub -> mappingInfo.getPatternValues().stream().filter(StringUtils::hasText).map(s -> sub + s))
+ .map(IgnoreUrl::new)
+ .forEach(url -> this.ignoreUrls.add(url));
+
+ System.out.println("ignoreUrls: " + ignoreUrls);
+ }
+ }
+
+ public boolean isIgnoreUrl(HttpServletRequest request) {
+ String method = request.getMethod();
+ String url = request.getRequestURI();
+
+ return this.ignoreUrls.stream().anyMatch(ignoreUrl -> ignoreUrl.isIgnoreUrl(method, url));
+ }
+
+ @Autowired
+ public void setSecurityConfig(SecurityConfig securityConfig) {
+ this.securityConfig = securityConfig;
+ }
+}
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/annotation/AuthorityType.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/annotation/AuthorityType.java
new file mode 100644
index 0000000..3da93b4
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/annotation/AuthorityType.java
@@ -0,0 +1,6 @@
+package day.gitlab.dolphin.common.security.annotation;
+
+public enum AuthorityType {
+ AND,
+ OR
+}
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/annotation/IgnoreUrl.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/annotation/IgnoreUrl.java
new file mode 100644
index 0000000..8080587
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/annotation/IgnoreUrl.java
@@ -0,0 +1,54 @@
+package day.gitlab.dolphin.common.security.annotation;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.util.AntPathMatcher;
+
+@Setter
+@Getter
+public class IgnoreUrl {
+
+ private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
+
+ private String method;
+
+ private String url;
+
+ public IgnoreUrl(String url) {
+ String urlUpperCase = url.toUpperCase();
+ if (urlUpperCase.startsWith("GET:")) {
+ this.method = "GET";
+ } else if (urlUpperCase.startsWith("HEAD:")) {
+ this.method = "HEAD";
+ } else if (urlUpperCase.startsWith("POST:")) {
+ this.method = "POST";
+ } else if (urlUpperCase.startsWith("PUT:")) {
+ this.method = "PUT";
+ } else if (urlUpperCase.startsWith("PATCH:")) {
+ this.method = "PATCH";
+ } else if (urlUpperCase.startsWith("DELETE:")) {
+ this.method = "DELETE";
+ } else if (urlUpperCase.startsWith("OPTIONS:")) {
+ this.method = "OPTIONS";
+ } else if (urlUpperCase.startsWith("TRACE:")) {
+ this.method = "TRACE";
+ } else {
+ this.method = null;
+ }
+
+ this.url = url.substring(urlUpperCase.indexOf(":") + 1);
+ }
+
+ public boolean isIgnoreUrl(String method, String url) {
+ if (!PATH_MATCHER.match(this.url, url)) {
+ return false;
+ }
+
+ return this.method == null || this.method.equalsIgnoreCase(method);
+ }
+
+ @Override
+ public String toString() {
+ return method == null ? url : method + ":" + url;
+ }
+}
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/config/SecurityConfig.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/config/SecurityConfig.java
new file mode 100644
index 0000000..892c6af
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/config/SecurityConfig.java
@@ -0,0 +1,24 @@
+package day.gitlab.dolphin.common.security.config;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Setter
+@Getter
+@Component
+@ConfigurationProperties("dolphin.security")
+public class SecurityConfig {
+
+ private boolean enabled = true;
+
+ private String ignoreUrls = "";
+
+ private String secret = "dolphin";
+
+ private long expire = 3600 * 1000L;
+
+ private long refreshTokenExpire = 7 * 24 * 3600 * 1000L;
+
+}
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/exception/AuthenticationException.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/exception/AuthenticationException.java
new file mode 100644
index 0000000..239cc07
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/exception/AuthenticationException.java
@@ -0,0 +1,12 @@
+package day.gitlab.dolphin.common.security.exception;
+
+import day.gitlab.dolphin.common.core.exception.BusinessException;
+import lombok.Getter;
+
+@Getter
+public class AuthenticationException extends BusinessException {
+
+ public AuthenticationException(int code, String message) {
+ super(code, message);
+ }
+}
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/exception/InvalidTokenException.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/exception/InvalidTokenException.java
new file mode 100644
index 0000000..5210b02
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/exception/InvalidTokenException.java
@@ -0,0 +1,14 @@
+package day.gitlab.dolphin.common.security.exception;
+
+import lombok.Getter;
+
+@Getter
+public class InvalidTokenException extends AuthenticationException {
+
+ private final String token;
+
+ public InvalidTokenException(String token) {
+ super(401, "Unauthorized: Invalid token");
+ this.token = token;
+ }
+}
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/exception/NotAuthorityException.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/exception/NotAuthorityException.java
new file mode 100644
index 0000000..1928c3a
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/exception/NotAuthorityException.java
@@ -0,0 +1,14 @@
+package day.gitlab.dolphin.common.security.exception;
+
+import lombok.Getter;
+
+@Getter
+public class NotAuthorityException extends AuthenticationException {
+
+ private final String[] userAuthorities;
+
+ public NotAuthorityException(String[] userAuthorities) {
+ super(403, "Forbidden: Insufficient permissions");
+ this.userAuthorities = userAuthorities;
+ }
+}
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/exception/NotLoginException.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/exception/NotLoginException.java
new file mode 100644
index 0000000..a36d7de
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/exception/NotLoginException.java
@@ -0,0 +1,8 @@
+package day.gitlab.dolphin.common.security.exception;
+
+public class NotLoginException extends AuthenticationException{
+
+ public NotLoginException() {
+ super(401, "Unauthorized");
+ }
+}
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/exception/TokenExpiredException.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/exception/TokenExpiredException.java
new file mode 100644
index 0000000..d757d5b
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/exception/TokenExpiredException.java
@@ -0,0 +1,20 @@
+package day.gitlab.dolphin.common.security.exception;
+
+import lombok.Getter;
+
+import java.util.Date;
+
+@Getter
+public class TokenExpiredException extends AuthenticationException {
+
+ private final String token;
+
+ private final Date expiration;
+
+ public TokenExpiredException(String token, Date expiration) {
+ super(401, "Unauthorized: Token expired");
+ this.token = token;
+ this.expiration = expiration;
+ }
+
+}
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/jwt/Jwt.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/jwt/Jwt.java
new file mode 100644
index 0000000..e77de70
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/jwt/Jwt.java
@@ -0,0 +1,70 @@
+package day.gitlab.dolphin.common.security.jwt;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.security.Keys;
+import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.util.StringUtils;
+
+import javax.crypto.SecretKey;
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
+import java.util.UUID;
+
+public class Jwt {
+
+ private final String secret;
+
+ private final long expire;
+
+ private final long refreshTokenExpire;
+
+ public Jwt(String secret, long expire, long refreshTokenExpire) {
+ this.secret = secret;
+ this.expire = expire;
+ this.refreshTokenExpire = refreshTokenExpire;
+ }
+
+ public String getTokenFromRequest(HttpServletRequest request) {
+ String token = request.getHeader("Authorization");
+ if (StringUtils.hasText(token) && token.startsWith("Bearer ")) {
+ return token.substring(7);
+ }
+ return null;
+ }
+
+ public String generateAccessToken(String userId) {
+ return Jwts.builder()
+ .subject(userId)
+ .id(UUID.randomUUID().toString())
+ .issuedAt(new Date())
+ .expiration(new Date(System.currentTimeMillis() + expire))
+ .claim("type", "access")
+ .signWith(getSigningKey())
+ .compact();
+ }
+
+ public String generateRefreshToken(String userId) {
+ return Jwts.builder()
+ .subject(userId)
+ .id(UUID.randomUUID().toString())
+ .issuedAt(new Date())
+ .expiration(new Date(System.currentTimeMillis() + refreshTokenExpire))
+ .claim("type", "refresh")
+ .signWith(getSigningKey())
+ .compact();
+ }
+
+ public Claims parseToken(String token) {
+ return Jwts.parser()
+ .verifyWith(getSigningKey())
+ .build()
+ .parseSignedClaims(token)
+ .getPayload();
+ }
+
+ private SecretKey getSigningKey() {
+ byte[] keyBytes = secret.getBytes(StandardCharsets.UTF_8);
+ return Keys.hmacShaKeyFor(keyBytes);
+ }
+}
diff --git a/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/jwt/JwtAuthenticationInitialize.java b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/jwt/JwtAuthenticationInitialize.java
new file mode 100644
index 0000000..c56c48a
--- /dev/null
+++ b/dolphin-commons/dolphin-common-security/src/main/java/day/gitlab/dolphin/common/security/jwt/JwtAuthenticationInitialize.java
@@ -0,0 +1,91 @@
+package day.gitlab.dolphin.common.security.jwt;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import day.gitlab.dolphin.common.security.Authentication;
+import day.gitlab.dolphin.common.security.AuthenticationInitialize;
+import day.gitlab.dolphin.common.security.AuthenticationProvider;
+import day.gitlab.dolphin.common.security.UserPrincipal;
+import day.gitlab.dolphin.common.security.config.SecurityConfig;
+import day.gitlab.dolphin.common.security.exception.InvalidTokenException;
+import day.gitlab.dolphin.common.security.exception.NotLoginException;
+import day.gitlab.dolphin.common.security.exception.TokenExpiredException;
+import io.jsonwebtoken.Claims;
+import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+@Component
+public class JwtAuthenticationInitialize implements AuthenticationInitialize {
+
+ private final SecurityConfig securityConfig;
+
+ private final StringRedisTemplate stringRedisTemplate;
+
+ private final AuthenticationProvider authenticationProvider;
+
+ public JwtAuthenticationInitialize(SecurityConfig securityConfig,
+ StringRedisTemplate stringRedisTemplate,
+ AuthenticationProvider authenticationProvider) {
+ this.securityConfig = securityConfig;
+ this.stringRedisTemplate = stringRedisTemplate;
+ this.authenticationProvider = authenticationProvider;
+ }
+
+ @Override
+ public Authentication initialize(HttpServletRequest request) {
+ Jwt jwt = new Jwt(securityConfig.getSecret(), securityConfig.getExpire(), securityConfig.getRefreshTokenExpire());
+
+ // 1、获取Token
+ String token = jwt.getTokenFromRequest(request);
+ if (token == null) {
+ throw new NotLoginException();
+ }
+ // 2、解析Token,获取用户ID
+ String userId;
+ Date expiration;
+ try {
+ Claims claims = jwt.parseToken(token);
+ userId = claims.getSubject();
+ expiration = claims.getExpiration();
+ Objects.requireNonNull(userId);
+ Objects.requireNonNull(expiration);
+ } catch (Exception e) {
+ throw new InvalidTokenException(token);
+ }
+ // 3、判断是否过期
+ if (expiration.before(new Date())) {
+ throw new TokenExpiredException(token, expiration);
+ }
+ // 4、从Redis或数据库中加载用户信息
+ UserPrincipal userPrincipal;
+ List userAuthorities;
+ try {
+ String userPrincipalJson = stringRedisTemplate.opsForValue().get("dolphin:user:info:" + userId);
+ ObjectMapper objectMapper = new ObjectMapper();
+ if (!StringUtils.hasText(userPrincipalJson)) {
+ userPrincipal = authenticationProvider.getUserPrincipal(userId);
+ stringRedisTemplate.opsForValue().set("dolphin:user:info:" + userId, objectMapper.writeValueAsString(userPrincipal));
+ } else {
+ userPrincipal = objectMapper.readValue(userPrincipalJson, UserPrincipal.class);
+ }
+ String userAuthJson = stringRedisTemplate.opsForValue().get("dolphin:user:auth:" + userId);
+ if (!StringUtils.hasText(userAuthJson)) {
+ userAuthorities = authenticationProvider.getUserAuthorities(userId);
+ stringRedisTemplate.opsForValue().set("dolphin:user:auth:" + userId, objectMapper.writeValueAsString(userAuthorities));
+ } else {
+ List> list = objectMapper.readValue(userAuthJson, List.class);
+ userAuthorities = list.stream().map(Object::toString).collect(Collectors.toList());
+ }
+ } catch (Exception e) {
+ throw new InvalidTokenException(token);
+ }
+
+ return new Authentication(userPrincipal, userAuthorities);
+ }
+}
diff --git a/dolphin-commons/pom.xml b/dolphin-commons/pom.xml
new file mode 100644
index 0000000..668ac46
--- /dev/null
+++ b/dolphin-commons/pom.xml
@@ -0,0 +1,18 @@
+
+
+ 4.0.0
+
+ day.gitlab
+ dolphin-backend
+ 0.0.1-SNAPSHOT
+
+
+ dolphin-commons
+ pom
+
+
+ dolphin-common-core
+ dolphin-common-security
+
+
diff --git a/dolphin-compose/pom.xml b/dolphin-compose/pom.xml
new file mode 100644
index 0000000..9d7a4d4
--- /dev/null
+++ b/dolphin-compose/pom.xml
@@ -0,0 +1,91 @@
+
+
+ 4.0.0
+
+ day.gitlab
+ dolphin-backend
+ 0.0.1-SNAPSHOT
+
+
+ dolphin-compose
+ jar
+
+
+
+
+ day.gitlab
+ dolphin-common-security
+ ${project.version}
+
+
+ day.gitlab
+ dolphin-module-rbac
+ ${project.version}
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+
+ com.mysql
+ mysql-connector-j
+ runtime
+
+
+ com.oracle.database.jdbc
+ ojdbc11
+ runtime
+
+
+ org.postgresql
+ postgresql
+ runtime
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
diff --git a/dolphin-compose/src/main/java/day/gitlab/dolphin/DolphinApplication.java b/dolphin-compose/src/main/java/day/gitlab/dolphin/DolphinApplication.java
new file mode 100644
index 0000000..2c31c6f
--- /dev/null
+++ b/dolphin-compose/src/main/java/day/gitlab/dolphin/DolphinApplication.java
@@ -0,0 +1,12 @@
+package day.gitlab.dolphin;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class DolphinApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(DolphinApplication.class, args);
+ }
+}
diff --git a/dolphin-compose/src/main/java/day/gitlab/dolphin/authorize/DolphinAuthenticationProvider.java b/dolphin-compose/src/main/java/day/gitlab/dolphin/authorize/DolphinAuthenticationProvider.java
new file mode 100644
index 0000000..eed41ee
--- /dev/null
+++ b/dolphin-compose/src/main/java/day/gitlab/dolphin/authorize/DolphinAuthenticationProvider.java
@@ -0,0 +1,26 @@
+package day.gitlab.dolphin.authorize;
+
+import day.gitlab.dolphin.common.security.AuthenticationProvider;
+import day.gitlab.dolphin.common.security.UserPrincipal;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Component
+public class DolphinAuthenticationProvider implements AuthenticationProvider {
+
+ @Override
+ public UserPrincipal getUserPrincipal(String userId) {
+ UserPrincipal userPrincipal = new UserPrincipal();
+ userPrincipal.setId(userId);
+ userPrincipal.setUsername(userId);
+ userPrincipal.setNickname(userId);
+ return userPrincipal;
+ }
+
+ @Override
+ public List getUserAuthorities(String userId) {
+ return new ArrayList<>();
+ }
+}
diff --git a/dolphin-compose/src/main/resources/application.yml b/dolphin-compose/src/main/resources/application.yml
new file mode 100644
index 0000000..6944be5
--- /dev/null
+++ b/dolphin-compose/src/main/resources/application.yml
@@ -0,0 +1,21 @@
+server:
+ port: 8080
+ servlet:
+ context-path: /
+spring:
+ application:
+ name: dolphin-compose
+ datasource:
+ type: com.zaxxer.hikari.HikariDataSource
+ driver-class-name: org.postgresql.Driver
+ url: jdbc:postgresql://110.42.60.129:10002/postgres
+ username: postgres
+ password: postgres
+ data:
+ redis:
+ host: 110.42.60.129
+ port: 10001
+ database: 0
+ password: 123456
+
+
diff --git a/dolphin-modules/dolphin-module-rbac/pom.xml b/dolphin-modules/dolphin-module-rbac/pom.xml
new file mode 100644
index 0000000..5d3e340
--- /dev/null
+++ b/dolphin-modules/dolphin-module-rbac/pom.xml
@@ -0,0 +1,58 @@
+
+
+ 4.0.0
+
+ day.gitlab
+ dolphin-modules
+ 0.0.1-SNAPSHOT
+
+
+ dolphin-module-rbac
+ jar
+
+
+
+ day.gitlab
+ dolphin-common-security
+ ${project.version}
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
+
+ com.mybatis-flex
+ mybatis-flex-spring-boot3-starter
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
diff --git a/dolphin-modules/dolphin-module-rbac/src/main/java/day/gitlab/dolphin/rbac/controller/RegionController.java b/dolphin-modules/dolphin-module-rbac/src/main/java/day/gitlab/dolphin/rbac/controller/RegionController.java
new file mode 100644
index 0000000..b0daa4c
--- /dev/null
+++ b/dolphin-modules/dolphin-module-rbac/src/main/java/day/gitlab/dolphin/rbac/controller/RegionController.java
@@ -0,0 +1,14 @@
+package day.gitlab.dolphin.rbac.controller;
+
+import day.gitlab.dolphin.rbac.service.RegionService;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/region")
+public class RegionController {
+
+ @Resource
+ private RegionService regionService;
+}
diff --git a/dolphin-modules/dolphin-module-rbac/src/main/java/day/gitlab/dolphin/rbac/entity/Region.java b/dolphin-modules/dolphin-module-rbac/src/main/java/day/gitlab/dolphin/rbac/entity/Region.java
new file mode 100644
index 0000000..f0e506b
--- /dev/null
+++ b/dolphin-modules/dolphin-module-rbac/src/main/java/day/gitlab/dolphin/rbac/entity/Region.java
@@ -0,0 +1,39 @@
+package day.gitlab.dolphin.rbac.entity;
+
+import com.mybatisflex.annotation.Id;
+import com.mybatisflex.annotation.KeyType;
+import com.mybatisflex.annotation.Table;
+import com.mybatisflex.core.keygen.KeyGenerators;
+import lombok.Data;
+
+import java.sql.Timestamp;
+
+@Data
+@Table("sys_rbac_region")
+public class Region {
+
+ @Id(keyType = KeyType.Generator, value = KeyGenerators.flexId)
+ private String id;
+
+ private String parentId;
+
+ private String parentCode;
+
+ private String rootId;
+
+ private String rootCode;
+
+ private String name;
+
+ private String code;
+
+ private String extCode;
+
+ private Integer sort;
+
+ private String description;
+
+ private Timestamp createTime;
+
+ private Timestamp updateTime;
+}
diff --git a/dolphin-modules/dolphin-module-rbac/src/main/java/day/gitlab/dolphin/rbac/entity/User.java b/dolphin-modules/dolphin-module-rbac/src/main/java/day/gitlab/dolphin/rbac/entity/User.java
new file mode 100644
index 0000000..4bfec07
--- /dev/null
+++ b/dolphin-modules/dolphin-module-rbac/src/main/java/day/gitlab/dolphin/rbac/entity/User.java
@@ -0,0 +1,19 @@
+package day.gitlab.dolphin.rbac.entity;
+
+import com.mybatisflex.annotation.Id;
+import com.mybatisflex.annotation.KeyType;
+import com.mybatisflex.annotation.Table;
+import com.mybatisflex.core.keygen.KeyGenerators;
+
+@Table("sys_rbac_user")
+public class User {
+
+ @Id(keyType = KeyType.Generator, value = KeyGenerators.flexId)
+ private String id;
+
+ private String username;
+
+ private String password;
+
+ private String nickname;
+}
diff --git a/dolphin-modules/dolphin-module-rbac/src/main/java/day/gitlab/dolphin/rbac/mapper/RegionMapper.java b/dolphin-modules/dolphin-module-rbac/src/main/java/day/gitlab/dolphin/rbac/mapper/RegionMapper.java
new file mode 100644
index 0000000..ff75fef
--- /dev/null
+++ b/dolphin-modules/dolphin-module-rbac/src/main/java/day/gitlab/dolphin/rbac/mapper/RegionMapper.java
@@ -0,0 +1,9 @@
+package day.gitlab.dolphin.rbac.mapper;
+
+import com.mybatisflex.core.BaseMapper;
+import day.gitlab.dolphin.rbac.entity.Region;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface RegionMapper extends BaseMapper {
+}
diff --git a/dolphin-modules/dolphin-module-rbac/src/main/java/day/gitlab/dolphin/rbac/service/RegionService.java b/dolphin-modules/dolphin-module-rbac/src/main/java/day/gitlab/dolphin/rbac/service/RegionService.java
new file mode 100644
index 0000000..13efcec
--- /dev/null
+++ b/dolphin-modules/dolphin-module-rbac/src/main/java/day/gitlab/dolphin/rbac/service/RegionService.java
@@ -0,0 +1,7 @@
+package day.gitlab.dolphin.rbac.service;
+
+import com.mybatisflex.core.service.IService;
+import day.gitlab.dolphin.rbac.entity.Region;
+
+public interface RegionService extends IService {
+}
diff --git a/dolphin-modules/dolphin-module-rbac/src/main/java/day/gitlab/dolphin/rbac/service/impl/RegionServiceImpl.java b/dolphin-modules/dolphin-module-rbac/src/main/java/day/gitlab/dolphin/rbac/service/impl/RegionServiceImpl.java
new file mode 100644
index 0000000..1c8267f
--- /dev/null
+++ b/dolphin-modules/dolphin-module-rbac/src/main/java/day/gitlab/dolphin/rbac/service/impl/RegionServiceImpl.java
@@ -0,0 +1,11 @@
+package day.gitlab.dolphin.rbac.service.impl;
+
+import com.mybatisflex.spring.service.impl.ServiceImpl;
+import day.gitlab.dolphin.rbac.entity.Region;
+import day.gitlab.dolphin.rbac.mapper.RegionMapper;
+import day.gitlab.dolphin.rbac.service.RegionService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class RegionServiceImpl extends ServiceImpl implements RegionService {
+}
diff --git a/dolphin-modules/pom.xml b/dolphin-modules/pom.xml
new file mode 100644
index 0000000..eb634fb
--- /dev/null
+++ b/dolphin-modules/pom.xml
@@ -0,0 +1,17 @@
+
+
+ 4.0.0
+
+ day.gitlab
+ dolphin-backend
+ 0.0.1-SNAPSHOT
+
+
+ dolphin-modules
+ pom
+
+
+ dolphin-module-rbac
+
+
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..b9d260c
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,102 @@
+
+
+ 4.0.0
+
+ day.gitlab
+ dolphin-backend
+ 0.0.1-SNAPSHOT
+ dolphin-backend
+ pom
+
+
+ 25
+ 3.5.8
+ 1.11.4
+ 0.13.0
+
+
+
+ dolphin-commons
+ dolphin-modules
+ dolphin-compose
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot.version}
+ pom
+ import
+
+
+
+ com.mybatis-flex
+ mybatis-flex-dependencies
+ ${mybatis-flex.version}
+ pom
+ import
+
+
+
+ io.jsonwebtoken
+ jjwt-api
+ ${jjwt.version}
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ ${jjwt.version}
+ runtime
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ ${jjwt.version}
+ runtime
+
+
+
+
+
+