mirror of https://github.com/elunez/eladmin
增加匿名访问注解,扩展PreAuthorize 匿名注解
测试用例: AnonymousAccessController.java 使用说明: 1. 在需要匿名访问的控制器方法上增加 @AnonymousAccess注解 2. 在需要匿名访问的控制器方法添加 @PreAuthorize("hasAnyRole('ROLE_ANONYMOUS')")pull/135/head
parent
85a8bb2e54
commit
8a8eb9d0a6
|
@ -35,6 +35,12 @@
|
||||||
<version>2.2</version>
|
<version>2.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-devtools</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!--jwt-->
|
<!--jwt-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package me.zhengjie.modules.monitor.rest;
|
package me.zhengjie.modules.monitor.rest;
|
||||||
|
|
||||||
import me.zhengjie.annotation.Limit;
|
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.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
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")
|
@Limit(key = "test", period = 60, count = 10, name = "testLimit", prefix = "limit")
|
||||||
@GetMapping("/limit")
|
@GetMapping("/limit")
|
||||||
|
@AnonymousAccess
|
||||||
public int testLimit() {
|
public int testLimit() {
|
||||||
return ATOMIC_INTEGER.incrementAndGet();
|
return ATOMIC_INTEGER.incrementAndGet();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
||||||
|
}
|
|
@ -1,13 +1,16 @@
|
||||||
package me.zhengjie.modules.security.config;
|
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.JwtAuthenticationEntryPoint;
|
||||||
import me.zhengjie.modules.security.security.JwtAuthorizationTokenFilter;
|
import me.zhengjie.modules.security.security.JwtAuthorizationTokenFilter;
|
||||||
import me.zhengjie.modules.security.service.JwtUserDetailsService;
|
import me.zhengjie.modules.security.service.JwtUserDetailsService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
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.bcrypt.BCryptPasswordEncoder;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
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
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
|
@ -30,6 +40,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private JwtUserDetailsService jwtUserDetailsService;
|
private JwtUserDetailsService jwtUserDetailsService;
|
||||||
|
@Autowired
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义基于JWT的安全过滤器
|
* 自定义基于JWT的安全过滤器
|
||||||
|
@ -50,6 +62,17 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
.passwordEncoder(passwordEncoderBean());
|
.passwordEncoder(passwordEncoderBean());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Bean
|
||||||
|
// public AnonymousAuthenticationFilter anonymousAuthenticationFilter() {
|
||||||
|
// AnonymousAuthenticationFilter authenticationFilter = new AnonymousAuthenticationFilter("anonymous");
|
||||||
|
// return authenticationFilter;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Bean
|
||||||
|
// public AnonymousAuthenticationProvider anonymousAuthenticationProvider() {
|
||||||
|
// return new AnonymousAuthenticationProvider("anonymous");
|
||||||
|
// }
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
GrantedAuthorityDefaults grantedAuthorityDefaults() {
|
GrantedAuthorityDefaults grantedAuthorityDefaults() {
|
||||||
// Remove the ROLE_ prefix
|
// Remove the ROLE_ prefix
|
||||||
|
@ -69,7 +92,19 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure(HttpSecurity httpSecurity) throws Exception {
|
protected void configure(HttpSecurity httpSecurity) throws Exception {
|
||||||
|
Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = applicationContext.getBean(RequestMappingHandlerMapping.class).getHandlerMethods();
|
||||||
|
Set<String> anonymousUrls = new HashSet<>();
|
||||||
|
for (Map.Entry<RequestMappingInfo, HandlerMethod> 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
|
httpSecurity
|
||||||
|
|
||||||
// 禁用 CSRF
|
// 禁用 CSRF
|
||||||
|
@ -91,7 +126,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
"/**/*.js"
|
"/**/*.js"
|
||||||
).anonymous()
|
).anonymous()
|
||||||
|
|
||||||
.antMatchers( HttpMethod.POST,"/auth/"+loginPath).anonymous()
|
.antMatchers(HttpMethod.POST, "/auth/" + loginPath).anonymous()
|
||||||
.antMatchers("/auth/vCode").anonymous()
|
.antMatchers("/auth/vCode").anonymous()
|
||||||
// 支付宝回调
|
// 支付宝回调
|
||||||
.antMatchers("/api/aliPay/return").anonymous()
|
.antMatchers("/api/aliPay/return").anonymous()
|
||||||
|
@ -114,12 +149,14 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
.antMatchers(HttpMethod.OPTIONS, "/**").anonymous()
|
.antMatchers(HttpMethod.OPTIONS, "/**").anonymous()
|
||||||
|
|
||||||
.antMatchers("/druid/**").anonymous()
|
.antMatchers("/druid/**").anonymous()
|
||||||
|
// 自定义匿名访问所有url放行
|
||||||
|
.antMatchers(anonymousUrls.toArray(new String[0])).anonymous()
|
||||||
// 所有请求都需要认证
|
// 所有请求都需要认证
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
|
|
||||||
// 防止iframe 造成跨域
|
// 防止iframe 造成跨域
|
||||||
.and().headers().frameOptions().disable();
|
.and().headers().frameOptions().disable();
|
||||||
|
|
||||||
httpSecurity
|
httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
|
||||||
.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,6 @@ public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Se
|
||||||
/**
|
/**
|
||||||
* 当用户尝试访问安全的REST资源而不提供任何凭据时,将调用此方法发送401 响应
|
* 当用户尝试访问安全的REST资源而不提供任何凭据时,将调用此方法发送401 响应
|
||||||
*/
|
*/
|
||||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException==null?"Unauthorized":authException.getMessage());
|
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException == null ? "Unauthorized" : authException.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,9 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
import me.zhengjie.modules.security.utils.JwtTokenUtil;
|
import me.zhengjie.modules.security.utils.JwtTokenUtil;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
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.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
@ -61,6 +63,10 @@ public class JwtAuthorizationTokenFilter extends OncePerRequestFilter {
|
||||||
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
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);
|
chain.doFilter(request, response);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue