package com.artfess.base.conf; import com.artfess.base.filter.JwtAuthorizationTokenFilter; import com.artfess.base.jwt.JwtAuthenticationEntryPoint; import com.artfess.base.jwt.JwtTokenHandler; import com.artfess.base.security.CustomAccessDeniedHandler; import com.artfess.base.security.CustomPwdEncoder; import com.artfess.base.security.HtDecisionManager; import com.artfess.base.security.HtFilterSecurityInterceptor; import com.artfess.base.util.StringUtil; import org.apache.commons.lang.ArrayUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.access.AccessDecisionManager; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.access.channel.ChannelProcessingFilter; import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; import javax.annotation.Resource; import java.util.List; @EnableWebSecurity @Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter{ private static final Logger logger = LoggerFactory.getLogger(WebSecurityConfig.class); @Resource UserDetailsService userDetailsService; @Resource JwtTokenHandler jwtTokenHandler; @Resource JwtConfig jwtConfig; @Value("${feign.encry.key:feignCallEncry}") private String encryKey; @Value("${artfess.security.ignore.httpUrls:''}") String permitAll; @Value("${artfess.security.deny.httpUrls:''}") String denyAll; @Value("${artfess.security.pswd.encoder:}") String passwordEncoder; @Value("${cors.enable:true}") Boolean corsEnable; @Resource JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; @Resource HtFilterSecurityInterceptor htFilterSecurityInterceptor; @Resource CustomAccessDeniedHandler customAccessDeniedHandler; @Value("${webjar.context:mvue,fvue,mobilevue}") private List resourceContext; // @Resource // List webExtends; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService) .passwordEncoder(getCustomPasswordEncoder()); } /** * 获取配置的自定义密码加密类 * @return */ public PasswordEncoder getCustomPasswordEncoder() { CustomPwdEncoder encoder = (CustomPwdEncoder) defaultPasswordEncoderBean(); if (StringUtil.isNotEmpty(passwordEncoder)) { try { logger.info("Use config password encoder : " + passwordEncoder); PasswordEncoder delegate = (PasswordEncoder) Class.forName(passwordEncoder).newInstance(); encoder.setDelegateEncoder(delegate); } catch (Exception e) { logger.error("Create custom password encoder config class["+passwordEncoder+"] failed."); } } return encoder; } @Bean public WebSecurityExtend emptyExtend() { return new WebSecurityEmptyExtend(); } @Bean public PasswordEncoder defaultPasswordEncoderBean() { return new CustomPwdEncoder(); } // 注册后台权限控制器 @Bean public AccessDecisionManager accessDecisionManager() { return new HtDecisionManager(); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(HttpSecurity httpSecurity) throws Exception { String[] permitAlls = new String[]{}; String[] denyAlls = new String[]{}; if(StringUtil.isNotEmpty(permitAll)){ permitAlls = permitAll.split(","); } // 将webjar中的resource资源添加到可匿名访问中 for(String rc : resourceContext) { permitAlls = (String[]) ArrayUtils.add(permitAlls, String.format("/%s/**", rc)); } if(StringUtil.isNotEmpty(denyAll)){ denyAlls = denyAll.split(","); } httpSecurity // we don't need CSRF because our token is invulnerable .csrf().disable() .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and() .exceptionHandling().accessDeniedHandler(customAccessDeniedHandler).and() // don't create session .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() .authorizeRequests() .antMatchers(permitAlls).permitAll() .antMatchers(denyAlls).denyAll() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() .antMatchers("/auth/**").permitAll() .antMatchers("/ueditor/**").permitAll() .anyRequest().authenticated() .accessDecisionManager(accessDecisionManager()); // Custom JWT based security filter JwtAuthorizationTokenFilter authenticationTokenFilter = new JwtAuthorizationTokenFilter(userDetailsService(), jwtTokenHandler, jwtConfig.getHeader()); authenticationTokenFilter.setEncryKey(encryKey); httpSecurity .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); httpSecurity .addFilterBefore(htFilterSecurityInterceptor, FilterSecurityInterceptor.class); httpSecurity .addFilterBefore(corsFilter(), ChannelProcessingFilter.class); // add custom filter // for (WebSecurityExtend extend : webExtends) { // for (Map.Entry, Filter> entry : extend.getCustomBeforeFilter().entrySet()) { // httpSecurity.addFilterBefore(entry.getValue(), entry.getKey()); // } // } // disable page caching httpSecurity .headers() .frameOptions().sameOrigin() // required to set for H2 else H2 Console will be blank. .cacheControl(); } @Override public void configure(WebSecurity web) throws Exception { // AuthenticationTokenFilter will ignore the below paths web .ignoring() .antMatchers( HttpMethod.POST, "/auth", "/sso/**", "/error", "/sys/sysLogs/v1/loginLogs", "/sys/sysLogs/v1/saveLogs", "/api/user/v1/user/loadUserByUsername", "/actuator/cert", "/uc/AuthorizationModel/v1/downloadFileLic", "/uc/AuthorizationModel/v1/uploadAuthorizationFile", "/form/formServiceController/v1/getFormAndBoExportXml", "/att/**", "/biz/warnInfo/messageCallback", "/biz/warnInfo/sendMessage", "/biz/scada/pointSystem/v1//saveScadaPointCache" ) .antMatchers( HttpMethod.GET, "/sso/**", "/sys/sysLogsSettings/v1/getSysLogsSettingStatusMap", "/sys/sysRoleAuth/v1/getMethodRoleAuth", "/file/v1/getLogoFile", /*"/flow/bpmTaskReminder/v1/executeTaskReminderJob",*/ "/flow/def/v1/bpmnXml", "/file/onlinePreviewController/v1/getFileByPathAndId**", "/file/onlinePreviewController/v1/getFileById**", "/portal/main/v1/appProperties", "/sys/sysProperties/v1/getByAlias", "/uc/tenantManage/v1/getTenantByCode", "/sys/sysProperties/v1/getDecryptBySysSetting", "/portal/shorturlManage/v1/getLongUrlByShortUrl", "/file/v1/downloadFile", "/**/downModel", "/**/exportExcel", //"/websocket/**", "/jmreport/**", "/interface-ui/**", "/att/**", "/att/waterPlan/downModel", "/dataway/api/v1/**" ) // allow anonymous resource requests .and() .ignoring() .antMatchers( HttpMethod.GET, "/", "/error", "/*.jpg", "/*.gif", "/*.html", "/favicon.ico", "/**/*.html", "/**/*.css", "/**/*.js", "/**/image", "/**/json", "/**/ftl", "/interface-ui/**", "/jmreport/**" ) .and() .ignoring() .antMatchers("/v2/api-docs", "/swagger-resources/configuration/ui", "/swagger-resources", "/swagger-resources/configuration/security", "/swagger-ui.html", "/proxy.stream", "/hystrix.stream", "/druid/**", "/hystrix/**", "/actuator/**", "/interface-ui/**", "/service/**", "/jmreport/**"); // 添加扩展的路径过滤 // for (WebSecurityExtend extend : webExtends) { // web // .ignoring() // .antMatchers(HttpMethod.POST, extend.getIgnoringPostUrl()) // .and() // .ignoring() // .antMatchers(HttpMethod.GET, extend.getIgnoringGetUrl()) // .and() // .ignoring() // .antMatchers(extend.getIgnoringUrl()); // } } /** * 允许跨域访问的源 * @return */ @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); if(corsEnable){ CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.addAllowedOrigin("*"); corsConfiguration.addAllowedHeader("*"); corsConfiguration.addAllowedMethod("*"); source.registerCorsConfiguration("/**", corsConfiguration); } return new CorsFilter(source); } @Bean public HtFilterSecurityInterceptor htFilterSecurityInterceptor(AccessDecisionManager accessDecisionManager) throws Exception{ HtFilterSecurityInterceptor htFilterSecurityInterceptor = new HtFilterSecurityInterceptor(); htFilterSecurityInterceptor.setAccessDecisionManager(accessDecisionManager); return htFilterSecurityInterceptor; } }