|
@@ -11,10 +11,12 @@ import org.springframework.context.ApplicationContext;
|
|
|
import org.springframework.context.annotation.Bean;
|
|
|
import org.springframework.http.HttpMethod;
|
|
|
import org.springframework.security.authentication.AuthenticationManager;
|
|
|
+import org.springframework.security.config.Customizer;
|
|
|
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
|
|
-import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
|
|
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
|
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
|
+import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
|
|
+import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
|
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
|
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
|
|
import org.springframework.security.web.SecurityFilterChain;
|
|
@@ -24,13 +26,17 @@ 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 org.springframework.web.util.pattern.PathPattern;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
import javax.annotation.security.PermitAll;
|
|
|
+import java.util.HashSet;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.Set;
|
|
|
|
|
|
+import static com.citu.framework.common.util.collection.CollectionUtils.convertList;
|
|
|
+
|
|
|
/**
|
|
|
* 自定义的 Spring Security 配置适配器实现
|
|
|
*
|
|
@@ -84,7 +90,7 @@ public class CituWebSecurityConfigurerAdapter {
|
|
|
|
|
|
/**
|
|
|
* 配置 URL 的安全配置
|
|
|
- *
|
|
|
+ * <p>
|
|
|
* anyRequest | 匹配所有请求路径
|
|
|
* access | SpringEl表达式结果为true时可以访问
|
|
|
* anonymous | 匿名可以访问
|
|
@@ -104,15 +110,15 @@ public class CituWebSecurityConfigurerAdapter {
|
|
|
// 登出
|
|
|
httpSecurity
|
|
|
// 开启跨域
|
|
|
- .cors().and()
|
|
|
+ .cors(Customizer.withDefaults())
|
|
|
// CSRF 禁用,因为不使用 Session
|
|
|
- .csrf().disable()
|
|
|
+ .csrf(AbstractHttpConfigurer::disable)
|
|
|
// 基于 token 机制,所以不需要 Session
|
|
|
- .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
|
|
|
- .headers().frameOptions().disable().and()
|
|
|
+ .sessionManagement(c -> c.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
|
|
+ .headers(c -> c.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
|
|
|
// 一堆自定义的 Spring Security 处理器
|
|
|
- .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
|
|
|
- .accessDeniedHandler(accessDeniedHandler);
|
|
|
+ .exceptionHandling(c -> c.authenticationEntryPoint(authenticationEntryPoint)
|
|
|
+ .accessDeniedHandler(accessDeniedHandler));
|
|
|
// 登录、登录暂时不使用 Spring Security 的拓展点,主要考虑一方面拓展多用户、多种登录方式相对复杂,一方面用户的学习成本较高
|
|
|
|
|
|
// 获得 @PermitAll 带来的 URL 列表,免登录
|
|
@@ -132,13 +138,14 @@ public class CituWebSecurityConfigurerAdapter {
|
|
|
.antMatchers(securityProperties.getPermitAllUrls().toArray(new String[0])).permitAll()
|
|
|
// 1.4 设置 App API 无需认证
|
|
|
.antMatchers(buildAppApi("/**")).permitAll()
|
|
|
+ // 1.5 验证码captcha 允许匿名访问
|
|
|
+ .antMatchers("/captcha/get", "/captcha/check").permitAll()
|
|
|
// ②:每个项目的自定义规则
|
|
|
.and().authorizeRequests(registry -> // 下面,循环设置自定义规则
|
|
|
authorizeRequestsCustomizers.forEach(customizer -> customizer.customize(registry)))
|
|
|
// ③:兜底规则,必须认证
|
|
|
.authorizeRequests()
|
|
|
- .anyRequest().authenticated()
|
|
|
- ;
|
|
|
+ .anyRequest().authenticated();
|
|
|
|
|
|
// 添加 Token Filter
|
|
|
httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
|
|
@@ -161,21 +168,30 @@ public class CituWebSecurityConfigurerAdapter {
|
|
|
if (!handlerMethod.hasMethodAnnotation(PermitAll.class)) {
|
|
|
continue;
|
|
|
}
|
|
|
- if (entry.getKey().getPatternsCondition() == null) {
|
|
|
+ Set<String> urls = new HashSet<>();
|
|
|
+ if (entry.getKey().getPatternsCondition() != null) {
|
|
|
+ urls.addAll(entry.getKey().getPatternsCondition().getPatterns());
|
|
|
+ }
|
|
|
+ if (entry.getKey().getPathPatternsCondition() != null) {
|
|
|
+ urls.addAll(convertList(entry.getKey().getPathPatternsCondition().getPatterns(), PathPattern::getPatternString));
|
|
|
+ }
|
|
|
+ if (urls.isEmpty()) {
|
|
|
continue;
|
|
|
}
|
|
|
- Set<String> urls = entry.getKey().getPatternsCondition().getPatterns();
|
|
|
+
|
|
|
// 特殊:使用 @RequestMapping 注解,并且未写 method 属性,此时认为都需要免登录
|
|
|
Set<RequestMethod> methods = entry.getKey().getMethodsCondition().getMethods();
|
|
|
- if (CollUtil.isEmpty(methods)) { //
|
|
|
+ if (CollUtil.isEmpty(methods)) {
|
|
|
result.putAll(HttpMethod.GET, urls);
|
|
|
result.putAll(HttpMethod.POST, urls);
|
|
|
result.putAll(HttpMethod.PUT, urls);
|
|
|
result.putAll(HttpMethod.DELETE, urls);
|
|
|
+ result.putAll(HttpMethod.HEAD, urls);
|
|
|
+ result.putAll(HttpMethod.PATCH, urls);
|
|
|
continue;
|
|
|
}
|
|
|
// 根据请求方法,添加到 result 结果
|
|
|
- methods.forEach(requestMethod -> {
|
|
|
+ entry.getKey().getMethodsCondition().getMethods().forEach(requestMethod -> {
|
|
|
switch (requestMethod) {
|
|
|
case GET:
|
|
|
result.putAll(HttpMethod.GET, urls);
|
|
@@ -189,6 +205,12 @@ public class CituWebSecurityConfigurerAdapter {
|
|
|
case DELETE:
|
|
|
result.putAll(HttpMethod.DELETE, urls);
|
|
|
break;
|
|
|
+ case HEAD:
|
|
|
+ result.putAll(HttpMethod.HEAD, urls);
|
|
|
+ break;
|
|
|
+ case PATCH:
|
|
|
+ result.putAll(HttpMethod.PATCH, urls);
|
|
|
+ break;
|
|
|
}
|
|
|
});
|
|
|
}
|