package com.jilongda.manage.config;
|
|
import com.jilongda.common.security.ExceptionHandleFilter;
|
import com.jilongda.manage.security.SecurityAccessDeniedHandler;
|
import com.jilongda.manage.security.SysUserDetailsService;
|
import com.jilongda.common.basic.Constant;
|
import com.jilongda.common.cache.CaffineCache;
|
import com.jilongda.common.security.SecurityUtils;
|
import com.jilongda.common.security.filter.AuthenticationFilter;
|
import com.jilongda.common.security.hadler.SecurityAuthenticationEntryPoint;
|
import com.jilongda.manage.security.AuthenticationProvider;
|
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;
|
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
|
|
/**
|
* 细粒度的访问控制
|
* <p>
|
* 注:需要使用注解@EnableGlobalMethodSecurity(prePostEnabled=true) 开启
|
*
|
* @author xiaochen
|
*/
|
@Configuration
|
@EnableWebSecurity
|
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
|
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
private final CaffineCache<String> accessTokenCache;
|
private final CaffineCache<String> refreshTokenCache;
|
private final PasswordEncoder passwordEncoder;
|
private final SecurityAccessDeniedHandler securityAccessDeniedHandler;
|
private final SecurityAuthenticationEntryPoint securityAuthenticationEntryPoint;
|
private final SysUserDetailsService loadUserDetailsService;
|
|
|
@Autowired
|
public WebSecurityConfig(CaffineCache<String> accessTokenCache, CaffineCache<String> refreshTokenCache, PasswordEncoder passwordEncoder, SecurityAccessDeniedHandler securityAccessDeniedHandler, SecurityAuthenticationEntryPoint securityAuthenticationEntryPoint, SysUserDetailsService loadUserDetailsService) {
|
this.accessTokenCache = accessTokenCache;
|
this.refreshTokenCache = refreshTokenCache;
|
this.passwordEncoder = passwordEncoder;
|
this.securityAccessDeniedHandler = securityAccessDeniedHandler;
|
this.securityAuthenticationEntryPoint = securityAuthenticationEntryPoint;
|
this.loadUserDetailsService = 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(Constant.DOC_LIST);
|
web.ignoring().antMatchers(Constant.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, "/**").permitAll()
|
// 其他都需要权限认证
|
.anyRequest()
|
.authenticated()
|
// RBAC 动态 url 认证
|
//.access("@rbacAuthorityService.hasPermission(request,authentication)")
|
// 其他所有请求需要身份认证
|
.and()
|
// 异常拦截
|
.exceptionHandling()
|
// 认证过的用户访问没有权限资源的处理
|
.accessDeniedHandler(securityAccessDeniedHandler)
|
// 未授权用户访问无权限时的处理
|
.authenticationEntryPoint(securityAuthenticationEntryPoint)
|
.and()
|
.sessionManagement()
|
.maximumSessions(5);
|
// 此处存在session共享的问题,如要共享session,则需要管理
|
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
|
// 访问控制时登录状态检查过滤器
|
http.addFilterBefore(new AuthenticationFilter(securityUtils()), UsernamePasswordAuthenticationFilter.class);
|
// 异常捕捉过滤器,必须在AuthenticationFilter之前才能捕捉到异常信息
|
http.addFilterBefore(new ExceptionHandleFilter(), AuthenticationFilter.class);
|
//禁用缓存
|
http.headers().cacheControl();
|
}
|
|
|
/**
|
* 验证管理器,在登录接口时用到
|
*
|
* @return
|
* @throws Exception
|
*/
|
@Bean
|
@Override
|
public AuthenticationManager authenticationManager() throws Exception {
|
return super.authenticationManager();
|
}
|
|
}
|