1 package cn.home1.oss.lib.security.starter;
2
3 import static com.google.common.collect.Lists.newArrayList;
4 import static java.util.stream.Collectors.toList;
5 import static org.apache.commons.lang3.StringUtils.isBlank;
6 import static org.springframework.core.Ordered.LOWEST_PRECEDENCE;
7
8 import com.google.common.collect.ImmutableList;
9
10 import cn.home1.oss.boot.autoconfigure.AppProperties;
11 import cn.home1.oss.lib.errorhandle.starter.ErrorHandleAutoConfiguration;
12 import cn.home1.oss.lib.security.CompositeAuthenticationProvider;
13 import cn.home1.oss.lib.security.api.BaseUserDetailsAuthenticationProvider;
14 import cn.home1.oss.lib.security.internal.feign.FeignTokenConfiguration;
15 import cn.home1.oss.lib.security.internal.zuul.ZuulTokenConfiguration;
16 import cn.home1.oss.lib.webmvc.starter.WebApplicationAutoConfiguration;
17
18 import lombok.extern.slf4j.Slf4j;
19
20 import org.springframework.beans.factory.annotation.Autowired;
21 import org.springframework.beans.factory.annotation.Qualifier;
22 import org.springframework.boot.autoconfigure.AutoConfigureAfter;
23 import org.springframework.boot.autoconfigure.AutoConfigureBefore;
24 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
25 import org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration;
26 import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
27 import org.springframework.context.annotation.Configuration;
28 import org.springframework.context.annotation.Import;
29 import org.springframework.core.annotation.Order;
30 import org.springframework.http.HttpMethod;
31 import org.springframework.security.authentication.AuthenticationManager;
32 import org.springframework.security.authentication.AuthenticationProvider;
33 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
34 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
35 import org.springframework.security.config.annotation.web.builders.WebSecurity;
36 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
37 import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
38 import org.springframework.security.web.context.NullSecurityContextRepository;
39
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Objects;
43
44
45
46
47
48
49
50
51
52
53
54
55
56 @AutoConfigureAfter({
57 WebApplicationAutoConfiguration.class,
58 ErrorHandleAutoConfiguration.class,
59 SecurityAutoConfiguration.class})
60 @AutoConfigureBefore(FallbackWebSecurityAutoConfiguration.class)
61 @ConditionalOnClass(WebSecurityConfigurerAdapter.class)
62 @Configuration
63 @Import({
64 VerifyCodeConfiguration.class,
65 PermitedRequestConfiguration.class,
66 PreAuthConfiguration.class,
67 BasicAuthConfiguration.class,
68 FormAuthConfiguration.class,
69 CsrfConfiguration.class,
70 MethodSecurityConfiguration.class,
71 FeignTokenConfiguration.class,
72 ZuulTokenConfiguration.class,
73 SwaggerConfiguration.class})
74 @Order(WebApplicationSecurityAutoConfiguration.ORDER_AFTER_MANAGEMENT_BEFORE_FALLBACK)
75 @Slf4j
76 public class WebApplicationSecurityAutoConfiguration extends WebSecurityConfigurerAdapter {
77
78
79
80
81 public static final int ORDER_AFTER_MANAGEMENT_BEFORE_FALLBACK = LOWEST_PRECEDENCE - 6;
82
83 @Autowired
84 private AppProperties appProperties;
85
86 @Qualifier(PermitedRequestConfiguration.PERMITED_REQUESTS)
87 @Autowired
88 public Map<String, List<String>> permitedRequests;
89
90 @Autowired
91 private AuthenticationManager parentAuthenticationManager;
92 @Qualifier(PreAuthConfiguration.PRE_AUTH_AUTHENTICATION_PROVIDER)
93 @Autowired(required = false)
94 private AuthenticationProvider preAuthAuthenticationProvider;
95 @Autowired(required = false)
96 @SuppressWarnings("rawtypes")
97 private BaseUserDetailsAuthenticationProvider userDetailsAuthenticationProvider;
98
99 @Autowired(required = false)
100 private List<SecurityConfigurer> securityConfigurers;
101
102
103
104
105 @Override
106 protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
107 for (final SecurityConfigurer configurer : this.sortedSecurityConfigurers()) {
108 configurer.configure(auth);
109 }
110
111 final List<AuthenticationProvider> providers = newArrayList(
112 this.preAuthAuthenticationProvider,
113 this.userDetailsAuthenticationProvider
114 ).stream().filter(Objects::nonNull).collect(toList());
115
116 if (!providers.isEmpty()) {
117 final CompositeAuthenticationProvider provider = new CompositeAuthenticationProvider();
118 provider.setDelegates(ImmutableList.copyOf(providers));
119
120 auth
121 .eraseCredentials(false)
122 .parentAuthenticationManager(this.parentAuthenticationManager)
123
124
125
126
127 .authenticationProvider(provider);
128 }
129 }
130
131 @Override
132 protected void configure(final HttpSecurity http) throws Exception {
133 http.securityContext().securityContextRepository(new NullSecurityContextRepository());
134
135 if (this.appProperties.getSecurityEnabled()) {
136
137
138
139 ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry =
140 http
141
142 .authorizeRequests();
143
144 for (final Map.Entry<String, List<String>> entry : this.permitedRequests.entrySet()) {
145 final String method = entry.getKey();
146 final HttpMethod httpMethod = isBlank(method) ? null : HttpMethod.valueOf(method);
147 final String[] patterns = entry.getValue().stream().toArray(String[]::new);
148 if (httpMethod == null) {
149 registry = registry.antMatchers(patterns).permitAll();
150 } else {
151 registry = registry.antMatchers(httpMethod, patterns).permitAll();
152 }
153 }
154 }
155
156 for (final SecurityConfigurer configurer : this.sortedSecurityConfigurers()) {
157 configurer.configure(http);
158 }
159
160 if (this.appProperties.getSecurityEnabled()) {
161 http
162 .authorizeRequests()
163 .anyRequest().authenticated();
164 } else {
165 http
166 .authorizeRequests()
167 .anyRequest().permitAll()
168 ;
169 }
170
171 http.headers().frameOptions().sameOrigin();
172 }
173
174 @Override
175 public void init(final WebSecurity web) throws Exception {
176 for (final SecurityConfigurer configurer : this.sortedSecurityConfigurers()) {
177 configurer.init(web);
178 }
179 super.init(web);
180 }
181
182 public List<SecurityConfigurer> sortedSecurityConfigurers() {
183 final List<SecurityConfigurer> all = this.securityConfigurers != null ? this.securityConfigurers : newArrayList();
184 final List<SecurityConfigurer> sorted = all.stream().sorted().collect(toList());
185 for (final SecurityConfigurer configurer : sorted) {
186 log.info("security configurer '{}', order '{}'", configurer.getClass().getName(), configurer.getOrder());
187 }
188 return sorted;
189 }
190 }