diff --git a/pom.xml b/pom.xml
index 24c7d6741..7ca5191a1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -19,7 +19,7 @@
https://github.com/YunaiV/ruoyi-vue-pro
- 1.0.0-snapshot
+ 1.1.0-snapshot
1.8
${java.version}
diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/security/SecurityConfiguration.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/security/SecurityConfiguration.java
new file mode 100644
index 000000000..8bb4bc9a6
--- /dev/null
+++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/security/SecurityConfiguration.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.adminserver.framework.security;
+
+import cn.iocoder.yudao.framework.web.config.WebProperties;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.Customizer;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
+
+import javax.annotation.Resource;
+
+@Configuration
+public class SecurityConfiguration {
+
+ @Resource
+ private WebProperties webProperties;
+
+ @Value("${spring.boot.admin.context-path:''}")
+ private String adminSeverContextPath;
+
+ @Bean
+ public Customizer.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer() {
+ return registry -> {
+ // 通用的接口,可匿名访问 TODO 芋艿:需要抽象出去
+ registry.antMatchers(api("/system/captcha/**")).anonymous();
+ // Spring Boot Admin Server 的安全配置 TODO 芋艿:需要抽象出去
+ registry.antMatchers(adminSeverContextPath).anonymous()
+ .antMatchers(adminSeverContextPath + "/**").anonymous();
+ // 短信回调 API
+ registry.antMatchers(api("/system/sms/callback/**")).anonymous();
+ };
+ }
+
+ private String api(String url) {
+ return webProperties.getApiPrefix() + url;
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-security/pom.xml b/yudao-framework/yudao-spring-boot-starter-security/pom.xml
index c62863bcb..45cc716b7 100644
--- a/yudao-framework/yudao-spring-boot-starter-security/pom.xml
+++ b/yudao-framework/yudao-spring-boot-starter-security/pom.xml
@@ -19,7 +19,12 @@
cn.iocoder.boot
yudao-common
- ${revision}
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java
index b9e0f34fc..94b3ecd14 100644
--- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.framework.security.config;
+import cn.iocoder.yudao.framework.security.core.aop.PreAuthenticatedAspect;
import cn.iocoder.yudao.framework.security.core.filter.JwtAuthenticationTokenFilter;
import cn.iocoder.yudao.framework.security.core.handler.AccessDeniedHandlerImpl;
import cn.iocoder.yudao.framework.security.core.handler.AuthenticationEntryPointImpl;
@@ -32,6 +33,14 @@ public class YudaoSecurityAutoConfiguration {
@Resource
private SecurityProperties securityProperties;
+ /**
+ * 处理用户未登陆拦截的切面的 Bean
+ */
+ @Bean
+ public PreAuthenticatedAspect preAuthenticatedAspect() {
+ return new PreAuthenticatedAspect();
+ }
+
/**
* 认证失败处理类 Bean
*/
diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java
index b1e432d2e..893d2b0f5 100644
--- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java
+++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java
@@ -14,10 +14,12 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@@ -41,9 +43,6 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
@Resource
private WebProperties webProperties;
- @Value("${spring.boot.admin.context-path:''}")
- private String adminSeverContextPath;
-
/**
* 自定义用户【认证】逻辑
*/
@@ -74,6 +73,13 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
*/
@Resource
private JwtAuthenticationTokenFilter authenticationTokenFilter;
+ /**
+ * 自定义的权限映射 Bean
+ *
+ * @see #configure(HttpSecurity)
+ */
+ @Resource
+ private Customizer.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer;
/**
* 由于 Spring Security 创建 AuthenticationManager 对象时,没声明 @Bean 注解,导致无法被注入
@@ -121,15 +127,16 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
.csrf().disable()
// 基于 token 机制,所以不需要 Session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
+ .headers().frameOptions().disable().and()
// 一堆自定义的 Spring Security 处理器
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler).and()
- // 设置每个请求的权限
- .authorizeRequests()
+ .logout().logoutUrl(api("/logout")).logoutSuccessHandler(logoutSuccessHandler); // 登出
+
+ // 设置每个请求的权限 ①:全局共享规则
+ httpSecurity.authorizeRequests()
// 登陆的接口,可匿名访问
.antMatchers(api("/login")).anonymous()
- // 通用的接口,可匿名访问 TODO 芋艿:需要抽象出去
- .antMatchers(api("/system/captcha/**")).anonymous()
// 静态资源,可匿名访问
.antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
// 文件的获取接口,可匿名访问
@@ -139,22 +146,15 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
.antMatchers("/swagger-resources/**").anonymous()
.antMatchers("/webjars/**").anonymous()
.antMatchers("/*/api-docs").anonymous()
- // Spring Boot Admin Server 的安全配置 TODO 芋艿:需要抽象出去
- .antMatchers(adminSeverContextPath).anonymous()
- .antMatchers(adminSeverContextPath + "/**").anonymous()
// Spring Boot Actuator 的安全配置
.antMatchers("/actuator").anonymous()
.antMatchers("/actuator/**").anonymous()
- // Druid 监控 TODO 芋艿:需要抽象出去
+ // Druid 监控 TODO 芋艿:等对接了 druid admin 后,在调整下。
.antMatchers("/druid/**").anonymous()
- // 短信回调 API TODO 芋艿:需要抽象出去
- .antMatchers(api("/system/sms/callback/**")).anonymous()
- .antMatchers(api("/user/**")).anonymous()
- // 除上面外的所有请求全部需要鉴权认证
- .anyRequest().authenticated()
- .and()
- .headers().frameOptions().disable();
- httpSecurity.logout().logoutUrl(api("/logout")).logoutSuccessHandler(logoutSuccessHandler);
+ // 设置每个请求的权限 ②:每个项目的自定义规则
+ .and().authorizeRequests(authorizeRequestsCustomizer)
+ // 设置每个请求的权限 ③:兜底规则,必须认证
+ .authorizeRequests().anyRequest().authenticated();
// 添加 JWT Filter
httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
}
diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/annotations/PreAuthenticated.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/annotations/PreAuthenticated.java
new file mode 100644
index 000000000..901936dd7
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/annotations/PreAuthenticated.java
@@ -0,0 +1,17 @@
+package cn.iocoder.yudao.framework.security.core.annotations;
+
+import java.lang.annotation.*;
+
+/**
+ * 声明用户需要登陆
+ *
+ * 为什么不使用 {@link org.springframework.security.access.prepost.PreAuthorize} 注解,原因是不通过时,抛出的是认证不通过,而不是未登陆
+ *
+ * @author 芋道源码
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+public @interface PreAuthenticated {
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/aop/PreAuthenticatedAspect.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/aop/PreAuthenticatedAspect.java
new file mode 100644
index 000000000..808afc393
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/aop/PreAuthenticatedAspect.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.framework.security.core.aop;
+
+import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
+import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+
+import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.UNAUTHORIZED;
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+
+@Aspect
+@Slf4j
+public class PreAuthenticatedAspect {
+
+ @Around("@annotation(preAuthenticated)")
+ public Object around(ProceedingJoinPoint joinPoint, PreAuthenticated preAuthenticated) throws Throwable {
+ if (SecurityFrameworkUtils.getLoginUser() == null) {
+ throw exception(UNAUTHORIZED);
+ }
+ return joinPoint.proceed();
+ }
+
+}
diff --git a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/framework/security/SecurityConfiguration.java b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/framework/security/SecurityConfiguration.java
new file mode 100644
index 000000000..e43f5e3e6
--- /dev/null
+++ b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/framework/security/SecurityConfiguration.java
@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.userserver.framework.security;
+
+import cn.iocoder.yudao.framework.web.config.WebProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.Customizer;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
+
+import javax.annotation.Resource;
+
+@Configuration
+public class SecurityConfiguration {
+
+ @Resource
+ private WebProperties webProperties;
+
+ @Bean
+ public Customizer.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer() {
+ return registry -> {
+ registry.antMatchers(api("/**")).anonymous(); // 默认 API 都是用户可访问
+ };
+ }
+
+ private String api(String url) {
+ return webProperties.getApiPrefix() + url;
+ }
+
+}
diff --git a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/infra/controller/HelloController.java b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/infra/controller/HelloController.java
index 617228750..6a3270fc2 100644
--- a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/infra/controller/HelloController.java
+++ b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/infra/controller/HelloController.java
@@ -1,6 +1,9 @@
package cn.iocoder.yudao.userserver.modules.infra.controller;
+import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.access.annotation.Secured;
+import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -15,4 +18,11 @@ public class HelloController {
public String hello(String hello) {
return "echo + " + hello;
}
+
+ @RequestMapping("/user/info")
+ @PreAuthenticated
+ public String xx() {
+ return "none";
+ }
+
}