package com.jilongda.applet.config; import com.jilongda.applet.security.AuthenticationProvider; import com.jilongda.applet.security.SysUserDetailsService; import com.jilongda.common.basic.Constant; import com.jilongda.common.cache.CaffineCache; import com.jilongda.common.redis.RedisAutoTemplate; import com.jilongda.common.security.SecurityUtils; import com.jilongda.common.security.filter.AuthenticationFilter; import com.jilongda.common.security.hadler.SecurityAuthenticationEntryPoint; import com.jilongda.common.swagger.SwaggerAutoConfiguration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 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.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; /** * 细粒度的访问控制 *

* 注:需要使用注解@EnableGlobalMethodSecurity(prePostEnabled=true) 开启 * * @author xiaochen */ @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private SecurityAuthenticationEntryPoint securityAuthenticationEntryPoint; @Autowired private RedisAutoTemplate redisAutoTemplate; @Autowired private CaffineCache accessTokenCache; @Autowired private CaffineCache refreshTokenCache; @Autowired private PasswordEncoder passwordEncoder; @Autowired private SysUserDetailsService loadUserDetailsService; /** * 应用重启token无效,可手动使令牌无效,管理了token的生命周期 * * @return */ @Bean public SecurityUtils securityUtils() { return new SecurityUtils(accessTokenCache, refreshTokenCache); // return new SecurityUtils(); } /** * 不需要认证的在此处放行,比如系统的一些字典请求 * 会包含Basic认证的请求。意思是如果请求在Basic中存在,在此处也存在,那么该请求的认证会被忽略 * 这种方式的优势是不走 Spring Security 过滤器链 * * @param web */ @Override public void configure(WebSecurity web) { web.ignoring().antMatchers(SwaggerAutoConfiguration.DOC_LIST); web.ignoring().antMatchers(Constant.APPLET_AUTH_WHITELIST); } /** * 使用自定义登录身份认证组件,自实现rest登录请求,不适用于在过滤其中实现 在过滤其中无法提供接口文档,维护不方便 * * @param auth */ @Override public void configure(AuthenticationManagerBuilder auth) { auth.authenticationProvider(new AuthenticationProvider(loadUserDetailsService,passwordEncoder)); } /** * Security各项配置 * * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { // 需要Basic认证的请求 http .cors().disable() // 关闭登录,自定义接口实现 .formLogin().disable() // 关闭httpBasic认证 .httpBasic().disable() // 关闭退出,自定义接口实现 .logout().disable() .csrf().disable() // 放在 Cookie 中返回前端,防止跨域伪造 //.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and() //.and() .authorizeRequests() // 跨域预检请求 .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 登录URL permitAll() 无需保护 ---> 此种方式配置忽略认证规则会走Spring Security 过滤器链,在过滤器链中,给请求放行 // 不需要保护的请求,但需要经过过滤连 //.antMatchers(HttpMethod.POST, "/login").permitAll() // 微信登录 .antMatchers(HttpMethod.GET, "/**/openId-by-jscode2session/**").permitAll() .antMatchers(HttpMethod.POST, "/login").permitAll() .antMatchers(HttpMethod.POST, "/code/login").permitAll() .antMatchers(HttpMethod.POST, "/sendCode").permitAll() .antMatchers(HttpMethod.POST, "/sendPassCode").permitAll() .antMatchers(HttpMethod.POST, "/pageResetPassword").permitAll() // 其他都需要权限认证 .anyRequest() .authenticated() // 其他所有请求需要身份认证 .and() // 异常拦截 .exceptionHandling() // 未授权用户访问无权限时的处理 .authenticationEntryPoint(securityAuthenticationEntryPoint); // 此处存在session共享的问题,如要共享session,则需要管理 http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); // 访问控制时登录状态检查过滤器 http.addFilterBefore(new AuthenticationFilter(securityUtils()), UsernamePasswordAuthenticationFilter.class); // 异常捕捉过滤器,必须在AuthenticationFilter之前才能捕捉到异常信息 http.addFilterBefore(new AuthenticationFilter(securityUtils()), AuthenticationFilter.class); //禁用缓存 http.headers().cacheControl(); } /** * 验证管理器,在登录接口时用到 * * @return * @throws Exception */ @Bean @Override public AuthenticationManager authenticationManager() throws Exception { return super.authenticationManager(); } }