From 8a8eb9d0a6b6717c3e2d6bd3f5d203c547e554cf Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 29 Sep 2019 21:38:00 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8C=BF=E5=90=8D=E8=AE=BF?= =?UTF-8?q?=E9=97=AE=E6=B3=A8=E8=A7=A3=EF=BC=8C=E6=89=A9=E5=B1=95PreAuthor?= =?UTF-8?q?ize=20=E5=8C=BF=E5=90=8D=E6=B3=A8=E8=A7=A3=20=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=94=A8=E4=BE=8B=EF=BC=9A=20AnonymousAccessController.java=20?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E8=AF=B4=E6=98=8E=EF=BC=9A=201.=20=E5=9C=A8?= =?UTF-8?q?=E9=9C=80=E8=A6=81=E5=8C=BF=E5=90=8D=E8=AE=BF=E9=97=AE=E7=9A=84?= =?UTF-8?q?=E6=8E=A7=E5=88=B6=E5=99=A8=E6=96=B9=E6=B3=95=E4=B8=8A=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20=20@AnonymousAccess=E6=B3=A8=E8=A7=A3=20=20=20=20?= =?UTF-8?q?=20=20=20=20=20=20=202.=20=E5=9C=A8=E9=9C=80=E8=A6=81=E5=8C=BF?= =?UTF-8?q?=E5=90=8D=E8=AE=BF=E9=97=AE=E7=9A=84=E6=8E=A7=E5=88=B6=E5=99=A8?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E6=B7=BB=E5=8A=A0=20@PreAuthorize("hasAnyRol?= =?UTF-8?q?e('ROLE=5FANONYMOUS')")?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- eladmin-system/pom.xml | 6 +++ .../rest/AnonymousAccessController.java | 38 ++++++++++++++++ .../modules/monitor/rest/LimitController.java | 2 + .../security/annotation/AnonymousAccess.java | 18 ++++++++ .../security/config/SecurityConfig.java | 45 +++++++++++++++++-- .../security/JwtAuthenticationEntryPoint.java | 2 +- .../security/JwtAuthorizationTokenFilter.java | 6 +++ 7 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 eladmin-system/src/main/java/me/zhengjie/modules/monitor/rest/AnonymousAccessController.java create mode 100644 eladmin-system/src/main/java/me/zhengjie/modules/security/annotation/AnonymousAccess.java diff --git a/eladmin-system/pom.xml b/eladmin-system/pom.xml index fbc1e007..09b9bcfc 100644 --- a/eladmin-system/pom.xml +++ b/eladmin-system/pom.xml @@ -35,6 +35,12 @@ 2.2 + + org.springframework.boot + spring-boot-devtools + true + + io.jsonwebtoken diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/monitor/rest/AnonymousAccessController.java b/eladmin-system/src/main/java/me/zhengjie/modules/monitor/rest/AnonymousAccessController.java new file mode 100644 index 00000000..1b304dc8 --- /dev/null +++ b/eladmin-system/src/main/java/me/zhengjie/modules/monitor/rest/AnonymousAccessController.java @@ -0,0 +1,38 @@ +package me.zhengjie.modules.monitor.rest; + +import me.zhengjie.modules.security.annotation.AnonymousAccess; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 匿名访问测试类 + */ +@RestController +@RequestMapping("api") +public class AnonymousAccessController { + private static final AtomicInteger ATOMIC_INTEGER = new AtomicInteger(); + + + @GetMapping("/anonymousAccess1") + @AnonymousAccess + public int testAnonymousAccess1() { + return ATOMIC_INTEGER.incrementAndGet(); + } + + @GetMapping("/anonymousAccess2") + @AnonymousAccess + @PreAuthorize("hasAnyRole('ROLE_ANONYMOUS')") + public int testAnonymousAccess2() { + return ATOMIC_INTEGER.incrementAndGet(); + } + + @GetMapping("/anonymousAccess3") + @PreAuthorize("hasAnyRole('ROLE_ANONYMOUS')") + public int testAnonymousAccess3() { + return ATOMIC_INTEGER.incrementAndGet(); + } +} diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/monitor/rest/LimitController.java b/eladmin-system/src/main/java/me/zhengjie/modules/monitor/rest/LimitController.java index 3a742cac..1802d3a5 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/monitor/rest/LimitController.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/monitor/rest/LimitController.java @@ -1,6 +1,7 @@ package me.zhengjie.modules.monitor.rest; import me.zhengjie.annotation.Limit; +import me.zhengjie.modules.security.annotation.AnonymousAccess; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -21,6 +22,7 @@ public class LimitController { */ @Limit(key = "test", period = 60, count = 10, name = "testLimit", prefix = "limit") @GetMapping("/limit") + @AnonymousAccess public int testLimit() { return ATOMIC_INTEGER.incrementAndGet(); } diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/security/annotation/AnonymousAccess.java b/eladmin-system/src/main/java/me/zhengjie/modules/security/annotation/AnonymousAccess.java new file mode 100644 index 00000000..661792cf --- /dev/null +++ b/eladmin-system/src/main/java/me/zhengjie/modules/security/annotation/AnonymousAccess.java @@ -0,0 +1,18 @@ +package me.zhengjie.modules.security.annotation; + +import me.zhengjie.aspect.LimitType; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author jacky + * 用于标记匿名访问方法 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface AnonymousAccess { + +} diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/security/config/SecurityConfig.java b/eladmin-system/src/main/java/me/zhengjie/modules/security/config/SecurityConfig.java index d10bd218..4aa256cb 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/security/config/SecurityConfig.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/security/config/SecurityConfig.java @@ -1,13 +1,16 @@ package me.zhengjie.modules.security.config; +import me.zhengjie.modules.security.annotation.AnonymousAccess; import me.zhengjie.modules.security.security.JwtAuthenticationEntryPoint; import me.zhengjie.modules.security.security.JwtAuthorizationTokenFilter; import me.zhengjie.modules.security.service.JwtUserDetailsService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; @@ -19,6 +22,13 @@ import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +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.HashSet; +import java.util.Map; +import java.util.Set; @Configuration @EnableWebSecurity @@ -30,6 +40,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private JwtUserDetailsService jwtUserDetailsService; + @Autowired + private ApplicationContext applicationContext; /** * 自定义基于JWT的安全过滤器 @@ -50,6 +62,17 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { .passwordEncoder(passwordEncoderBean()); } +// @Bean +// public AnonymousAuthenticationFilter anonymousAuthenticationFilter() { +// AnonymousAuthenticationFilter authenticationFilter = new AnonymousAuthenticationFilter("anonymous"); +// return authenticationFilter; +// } +// +// @Bean +// public AnonymousAuthenticationProvider anonymousAuthenticationProvider() { +// return new AnonymousAuthenticationProvider("anonymous"); +// } + @Bean GrantedAuthorityDefaults grantedAuthorityDefaults() { // Remove the ROLE_ prefix @@ -69,7 +92,19 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity httpSecurity) throws Exception { - + Map handlerMethodMap = applicationContext.getBean(RequestMappingHandlerMapping.class).getHandlerMethods(); + Set anonymousUrls = new HashSet<>(); + for (Map.Entry infoEntry : handlerMethodMap.entrySet()) { + HandlerMethod handlerMethod = infoEntry.getValue(); + AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class); + PreAuthorize preAuthorize = handlerMethod.getMethodAnnotation(PreAuthorize.class); + // PreAuthorize("hasAnyRole('ROLE_ANONYMOUS')") 和 AnonymousAccess + if (null != preAuthorize && preAuthorize.value().contains("ROLE_ANONYMOUS")) { + anonymousUrls.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + } else if (null != anonymousAccess && null == preAuthorize) { + anonymousUrls.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + } + } httpSecurity // 禁用 CSRF @@ -91,7 +126,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { "/**/*.js" ).anonymous() - .antMatchers( HttpMethod.POST,"/auth/"+loginPath).anonymous() + .antMatchers(HttpMethod.POST, "/auth/" + loginPath).anonymous() .antMatchers("/auth/vCode").anonymous() // 支付宝回调 .antMatchers("/api/aliPay/return").anonymous() @@ -114,12 +149,14 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { .antMatchers(HttpMethod.OPTIONS, "/**").anonymous() .antMatchers("/druid/**").anonymous() + // 自定义匿名访问所有url放行 + .antMatchers(anonymousUrls.toArray(new String[0])).anonymous() // 所有请求都需要认证 .anyRequest().authenticated() + // 防止iframe 造成跨域 .and().headers().frameOptions().disable(); - httpSecurity - .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); + httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); } } diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/security/security/JwtAuthenticationEntryPoint.java b/eladmin-system/src/main/java/me/zhengjie/modules/security/security/JwtAuthenticationEntryPoint.java index f1504671..9dfbb938 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/security/security/JwtAuthenticationEntryPoint.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/security/security/JwtAuthenticationEntryPoint.java @@ -21,6 +21,6 @@ public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Se /** * 当用户尝试访问安全的REST资源而不提供任何凭据时,将调用此方法发送401 响应 */ - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException==null?"Unauthorized":authException.getMessage()); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException == null ? "Unauthorized" : authException.getMessage()); } } diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/security/security/JwtAuthorizationTokenFilter.java b/eladmin-system/src/main/java/me/zhengjie/modules/security/security/JwtAuthorizationTokenFilter.java index 1693bcc1..8ca24fdf 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/security/security/JwtAuthorizationTokenFilter.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/security/security/JwtAuthorizationTokenFilter.java @@ -5,7 +5,9 @@ import lombok.extern.slf4j.Slf4j; import me.zhengjie.modules.security.utils.JwtTokenUtil; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; @@ -61,6 +63,10 @@ public class JwtAuthorizationTokenFilter extends OncePerRequestFilter { authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } + } else { +// AnonymousAuthenticationToken anonymousAuthenticationToken = new AnonymousAuthenticationToken("anonymous", "anonymousUser", AuthorityUtils.createAuthorityList(new String[]{"ROLE_ANONYMOUS"})); +// anonymousAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); +// SecurityContextHolder.getContext().setAuthentication(anonymousAuthenticationToken); } chain.doFilter(request, response); }