Commit 689171c18dca9304df6edd9efd1a90a1a9b35a1e
1 parent
0439a550
增加 @PreAuthenticated 注解,实现登陆的拦截
Showing
9 changed files
with
155 additions
and
21 deletions
pom.xml
| ... | ... | @@ -19,7 +19,7 @@ |
| 19 | 19 | <url>https://github.com/YunaiV/ruoyi-vue-pro</url> |
| 20 | 20 | |
| 21 | 21 | <properties> |
| 22 | - <revision>1.0.0-snapshot</revision> | |
| 22 | + <revision>1.1.0-snapshot</revision> | |
| 23 | 23 | <!-- Maven 相关 --> |
| 24 | 24 | <java.version>1.8</java.version> |
| 25 | 25 | <maven.compiler.source>${java.version}</maven.compiler.source> | ... | ... |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/security/SecurityConfiguration.java
0 → 100644
| 1 | +package cn.iocoder.yudao.adminserver.framework.security; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.web.config.WebProperties; | |
| 4 | +import org.springframework.beans.factory.annotation.Value; | |
| 5 | +import org.springframework.context.annotation.Bean; | |
| 6 | +import org.springframework.context.annotation.Configuration; | |
| 7 | +import org.springframework.security.config.Customizer; | |
| 8 | +import org.springframework.security.config.annotation.web.builders.HttpSecurity; | |
| 9 | +import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; | |
| 10 | + | |
| 11 | +import javax.annotation.Resource; | |
| 12 | + | |
| 13 | +@Configuration | |
| 14 | +public class SecurityConfiguration { | |
| 15 | + | |
| 16 | + @Resource | |
| 17 | + private WebProperties webProperties; | |
| 18 | + | |
| 19 | + @Value("${spring.boot.admin.context-path:''}") | |
| 20 | + private String adminSeverContextPath; | |
| 21 | + | |
| 22 | + @Bean | |
| 23 | + public Customizer<ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer() { | |
| 24 | + return registry -> { | |
| 25 | + // 通用的接口,可匿名访问 TODO 芋艿:需要抽象出去 | |
| 26 | + registry.antMatchers(api("/system/captcha/**")).anonymous(); | |
| 27 | + // Spring Boot Admin Server 的安全配置 TODO 芋艿:需要抽象出去 | |
| 28 | + registry.antMatchers(adminSeverContextPath).anonymous() | |
| 29 | + .antMatchers(adminSeverContextPath + "/**").anonymous(); | |
| 30 | + // 短信回调 API | |
| 31 | + registry.antMatchers(api("/system/sms/callback/**")).anonymous(); | |
| 32 | + }; | |
| 33 | + } | |
| 34 | + | |
| 35 | + private String api(String url) { | |
| 36 | + return webProperties.getApiPrefix() + url; | |
| 37 | + } | |
| 38 | + | |
| 39 | +} | ... | ... |
yudao-framework/yudao-spring-boot-starter-security/pom.xml
| ... | ... | @@ -19,7 +19,12 @@ |
| 19 | 19 | <dependency> |
| 20 | 20 | <groupId>cn.iocoder.boot</groupId> |
| 21 | 21 | <artifactId>yudao-common</artifactId> |
| 22 | - <version>${revision}</version> | |
| 22 | + </dependency> | |
| 23 | + | |
| 24 | + <!-- Spring 核心 --> | |
| 25 | + <dependency> | |
| 26 | + <groupId>org.springframework.boot</groupId> | |
| 27 | + <artifactId>spring-boot-starter-aop</artifactId> | |
| 23 | 28 | </dependency> |
| 24 | 29 | |
| 25 | 30 | <!-- Web 相关 --> | ... | ... |
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java
| 1 | 1 | package cn.iocoder.yudao.framework.security.config; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.security.core.aop.PreAuthenticatedAspect; | |
| 3 | 4 | import cn.iocoder.yudao.framework.security.core.filter.JwtAuthenticationTokenFilter; |
| 4 | 5 | import cn.iocoder.yudao.framework.security.core.handler.AccessDeniedHandlerImpl; |
| 5 | 6 | import cn.iocoder.yudao.framework.security.core.handler.AuthenticationEntryPointImpl; |
| ... | ... | @@ -33,6 +34,14 @@ public class YudaoSecurityAutoConfiguration { |
| 33 | 34 | private SecurityProperties securityProperties; |
| 34 | 35 | |
| 35 | 36 | /** |
| 37 | + * 处理用户未登陆拦截的切面的 Bean | |
| 38 | + */ | |
| 39 | + @Bean | |
| 40 | + public PreAuthenticatedAspect preAuthenticatedAspect() { | |
| 41 | + return new PreAuthenticatedAspect(); | |
| 42 | + } | |
| 43 | + | |
| 44 | + /** | |
| 36 | 45 | * 认证失败处理类 Bean |
| 37 | 46 | */ |
| 38 | 47 | @Bean | ... | ... |
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; |
| 14 | 14 | import org.springframework.context.annotation.Configuration; |
| 15 | 15 | import org.springframework.http.HttpMethod; |
| 16 | 16 | import org.springframework.security.authentication.AuthenticationManager; |
| 17 | +import org.springframework.security.config.Customizer; | |
| 17 | 18 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; |
| 18 | 19 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; |
| 19 | 20 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
| 20 | 21 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; |
| 22 | +import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; | |
| 21 | 23 | import org.springframework.security.config.http.SessionCreationPolicy; |
| 22 | 24 | import org.springframework.security.core.userdetails.UserDetailsService; |
| 23 | 25 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; |
| ... | ... | @@ -41,9 +43,6 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap |
| 41 | 43 | @Resource |
| 42 | 44 | private WebProperties webProperties; |
| 43 | 45 | |
| 44 | - @Value("${spring.boot.admin.context-path:''}") | |
| 45 | - private String adminSeverContextPath; | |
| 46 | - | |
| 47 | 46 | /** |
| 48 | 47 | * 自定义用户【认证】逻辑 |
| 49 | 48 | */ |
| ... | ... | @@ -74,6 +73,13 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap |
| 74 | 73 | */ |
| 75 | 74 | @Resource |
| 76 | 75 | private JwtAuthenticationTokenFilter authenticationTokenFilter; |
| 76 | + /** | |
| 77 | + * 自定义的权限映射 Bean | |
| 78 | + * | |
| 79 | + * @see #configure(HttpSecurity) | |
| 80 | + */ | |
| 81 | + @Resource | |
| 82 | + private Customizer<ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer; | |
| 77 | 83 | |
| 78 | 84 | /** |
| 79 | 85 | * 由于 Spring Security 创建 AuthenticationManager 对象时,没声明 @Bean 注解,导致无法被注入 |
| ... | ... | @@ -121,15 +127,16 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap |
| 121 | 127 | .csrf().disable() |
| 122 | 128 | // 基于 token 机制,所以不需要 Session |
| 123 | 129 | .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() |
| 130 | + .headers().frameOptions().disable().and() | |
| 124 | 131 | // 一堆自定义的 Spring Security 处理器 |
| 125 | 132 | .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint) |
| 126 | 133 | .accessDeniedHandler(accessDeniedHandler).and() |
| 127 | - // 设置每个请求的权限 | |
| 128 | - .authorizeRequests() | |
| 134 | + .logout().logoutUrl(api("/logout")).logoutSuccessHandler(logoutSuccessHandler); // 登出 | |
| 135 | + | |
| 136 | + // 设置每个请求的权限 ①:全局共享规则 | |
| 137 | + httpSecurity.authorizeRequests() | |
| 129 | 138 | // 登陆的接口,可匿名访问 |
| 130 | 139 | .antMatchers(api("/login")).anonymous() |
| 131 | - // 通用的接口,可匿名访问 TODO 芋艿:需要抽象出去 | |
| 132 | - .antMatchers(api("/system/captcha/**")).anonymous() | |
| 133 | 140 | // 静态资源,可匿名访问 |
| 134 | 141 | .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll() |
| 135 | 142 | // 文件的获取接口,可匿名访问 |
| ... | ... | @@ -139,22 +146,15 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap |
| 139 | 146 | .antMatchers("/swagger-resources/**").anonymous() |
| 140 | 147 | .antMatchers("/webjars/**").anonymous() |
| 141 | 148 | .antMatchers("/*/api-docs").anonymous() |
| 142 | - // Spring Boot Admin Server 的安全配置 TODO 芋艿:需要抽象出去 | |
| 143 | - .antMatchers(adminSeverContextPath).anonymous() | |
| 144 | - .antMatchers(adminSeverContextPath + "/**").anonymous() | |
| 145 | 149 | // Spring Boot Actuator 的安全配置 |
| 146 | 150 | .antMatchers("/actuator").anonymous() |
| 147 | 151 | .antMatchers("/actuator/**").anonymous() |
| 148 | - // Druid 监控 TODO 芋艿:需要抽象出去 | |
| 152 | + // Druid 监控 TODO 芋艿:等对接了 druid admin 后,在调整下。 | |
| 149 | 153 | .antMatchers("/druid/**").anonymous() |
| 150 | - // 短信回调 API TODO 芋艿:需要抽象出去 | |
| 151 | - .antMatchers(api("/system/sms/callback/**")).anonymous() | |
| 152 | - .antMatchers(api("/user/**")).anonymous() | |
| 153 | - // 除上面外的所有请求全部需要鉴权认证 | |
| 154 | - .anyRequest().authenticated() | |
| 155 | - .and() | |
| 156 | - .headers().frameOptions().disable(); | |
| 157 | - httpSecurity.logout().logoutUrl(api("/logout")).logoutSuccessHandler(logoutSuccessHandler); | |
| 154 | + // 设置每个请求的权限 ②:每个项目的自定义规则 | |
| 155 | + .and().authorizeRequests(authorizeRequestsCustomizer) | |
| 156 | + // 设置每个请求的权限 ③:兜底规则,必须认证 | |
| 157 | + .authorizeRequests().anyRequest().authenticated(); | |
| 158 | 158 | // 添加 JWT Filter |
| 159 | 159 | httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); |
| 160 | 160 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/annotations/PreAuthenticated.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.security.core.annotations; | |
| 2 | + | |
| 3 | +import java.lang.annotation.*; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * 声明用户需要登陆 | |
| 7 | + * | |
| 8 | + * 为什么不使用 {@link org.springframework.security.access.prepost.PreAuthorize} 注解,原因是不通过时,抛出的是认证不通过,而不是未登陆 | |
| 9 | + * | |
| 10 | + * @author 芋道源码 | |
| 11 | + */ | |
| 12 | +@Target({ElementType.METHOD}) | |
| 13 | +@Retention(RetentionPolicy.RUNTIME) | |
| 14 | +@Inherited | |
| 15 | +@Documented | |
| 16 | +public @interface PreAuthenticated { | |
| 17 | +} | ... | ... |
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/aop/PreAuthenticatedAspect.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.security.core.aop; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; | |
| 4 | +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; | |
| 5 | +import lombok.extern.slf4j.Slf4j; | |
| 6 | +import org.aspectj.lang.ProceedingJoinPoint; | |
| 7 | +import org.aspectj.lang.annotation.Around; | |
| 8 | +import org.aspectj.lang.annotation.Aspect; | |
| 9 | + | |
| 10 | +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.UNAUTHORIZED; | |
| 11 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 12 | + | |
| 13 | +@Aspect | |
| 14 | +@Slf4j | |
| 15 | +public class PreAuthenticatedAspect { | |
| 16 | + | |
| 17 | + @Around("@annotation(preAuthenticated)") | |
| 18 | + public Object around(ProceedingJoinPoint joinPoint, PreAuthenticated preAuthenticated) throws Throwable { | |
| 19 | + if (SecurityFrameworkUtils.getLoginUser() == null) { | |
| 20 | + throw exception(UNAUTHORIZED); | |
| 21 | + } | |
| 22 | + return joinPoint.proceed(); | |
| 23 | + } | |
| 24 | + | |
| 25 | +} | ... | ... |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/framework/security/SecurityConfiguration.java
0 → 100644
| 1 | +package cn.iocoder.yudao.userserver.framework.security; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.web.config.WebProperties; | |
| 4 | +import org.springframework.context.annotation.Bean; | |
| 5 | +import org.springframework.context.annotation.Configuration; | |
| 6 | +import org.springframework.security.config.Customizer; | |
| 7 | +import org.springframework.security.config.annotation.web.builders.HttpSecurity; | |
| 8 | +import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; | |
| 9 | + | |
| 10 | +import javax.annotation.Resource; | |
| 11 | + | |
| 12 | +@Configuration | |
| 13 | +public class SecurityConfiguration { | |
| 14 | + | |
| 15 | + @Resource | |
| 16 | + private WebProperties webProperties; | |
| 17 | + | |
| 18 | + @Bean | |
| 19 | + public Customizer<ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer() { | |
| 20 | + return registry -> { | |
| 21 | + registry.antMatchers(api("/**")).anonymous(); // 默认 API 都是用户可访问 | |
| 22 | + }; | |
| 23 | + } | |
| 24 | + | |
| 25 | + private String api(String url) { | |
| 26 | + return webProperties.getApiPrefix() + url; | |
| 27 | + } | |
| 28 | + | |
| 29 | +} | ... | ... |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/infra/controller/HelloController.java
| 1 | 1 | package cn.iocoder.yudao.userserver.modules.infra.controller; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; | |
| 3 | 4 | import lombok.extern.slf4j.Slf4j; |
| 5 | +import org.springframework.security.access.annotation.Secured; | |
| 6 | +import org.springframework.security.access.prepost.PreAuthorize; | |
| 4 | 7 | import org.springframework.web.bind.annotation.RequestMapping; |
| 5 | 8 | import org.springframework.web.bind.annotation.RestController; |
| 6 | 9 | |
| ... | ... | @@ -15,4 +18,11 @@ public class HelloController { |
| 15 | 18 | public String hello(String hello) { |
| 16 | 19 | return "echo + " + hello; |
| 17 | 20 | } |
| 21 | + | |
| 22 | + @RequestMapping("/user/info") | |
| 23 | + @PreAuthenticated | |
| 24 | + public String xx() { | |
| 25 | + return "none"; | |
| 26 | + } | |
| 27 | + | |
| 18 | 28 | } | ... | ... |