mark v1 SecurityConfig

package cn.efunbox.cms.configuration;

import cn.efunbox.afw.core.entity.ApiCode;
import cn.efunbox.afw.core.entity.ApiResult;
import cn.efunbox.cms.code.CmsWebApiCode;
import cn.efunbox.cms.interceptor.LoginInterceptor;
import cn.efunbox.cms.security.CmsAuthenticationProvider;
import cn.efunbox.cms.security.CmsUserDetailsService;
import cn.efunbox.web.common.util.HttpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
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.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import org.springframework.security.web.authentication.session.*;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.WebUtils;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

/**
* 安全配置中心
* @author by tomas
* @date 2017-06-06 15:30:00
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)//允许进入页面方法前检验
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

private static final Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);

@Bean
public UserDetailsService userDetailsService() {
return new CmsUserDetailsService();
}

@Bean
public CmsAuthenticationProvider cmsAuthenticationProvider() {
return new CmsAuthenticationProvider();
}

/**
* 设置那些 URL 忽略权限
* @param web
* @throws Exception
*/
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
web.ignoring().antMatchers(HttpMethod.GET,"/login/**");
}

@Override
protected void configure(HttpSecurity http) throws Exception {

http
.authorizeRequests()
.anyRequest().authenticated()
//先去掉 csrf
.and().csrf().disable()
//.and().csrf().ignoringAntMatchers("/login","/logout").csrfTokenRepository(csrfTokenRepository()).and()
.addFilterAfter(csrfHeaderFilter(), SessionManagementFilter.class)
.authorizeRequests().antMatchers("/login").permitAll();

http
.formLogin().successHandler(new RestAuthenticationSuccessHandler())
.failureHandler(new RestAuthenticationFailureHandler())
.permitAll()
.and()
.logout().logoutSuccessHandler(new RestLogoutSuccessHandler())
.deleteCookies("JSESSIONID", "X-XSRF-TOKEN")
.permitAll();

http.sessionManagement()
.sessionAuthenticationStrategy(sessionAuthenticationStrategy())
.and()
.addFilter(concurrentSessionFilter());

http.exceptionHandling().authenticationEntryPoint(new RestAuthenticationEntryPoint());
// http
// .rememberMe()
// .rememberMeCookieName("")
// .tokenValiditySeconds(200000)
// .rememberMeServices(rememberMeServices);

}

/**
* 自定义 认证密码 和 获取用户 服务
* @param auth
* @throws Exception
*/
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(cmsAuthenticationProvider())
.userDetailsService(userDetailsService());
}

@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}

/**
* csrf 过滤器 请求必须
* @return
*/
private Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {

@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {

CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null || token != null
&& !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
};
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");//repository.setSessionAttributeName(("X-XSRF-TOKEN"));
return repository;
}

/**
* 注册自定义的SessionRegistry
*/
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}

/**
* 注册自定义 sessionAuthenticationStrategy
* 设置 ConcurrentSessionControlAuthenticationStrategy 控制并发
* 设置 SessionFixationProtectionStrategy 可以防盗session
* 设置 RegisterSessionAuthenticationStrategy 触发了注册新sessin
*/
@Bean
public CompositeSessionAuthenticationStrategy sessionAuthenticationStrategy() {
ConcurrentSessionControlAuthenticationStrategy concurrentSessionControlAuthenticationStrategy = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry());
concurrentSessionControlAuthenticationStrategy.setMaximumSessions(20);
concurrentSessionControlAuthenticationStrategy.setExceptionIfMaximumExceeded(true);
SessionFixationProtectionStrategy sessionFixationProtectionStrategy = new SessionFixationProtectionStrategy();
RegisterSessionAuthenticationStrategy registerSessionStrategy = new RegisterSessionAuthenticationStrategy(sessionRegistry());
CompositeSessionAuthenticationStrategy sessionAuthenticationStrategy = new CompositeSessionAuthenticationStrategy(
Arrays.asList(concurrentSessionControlAuthenticationStrategy, sessionFixationProtectionStrategy, registerSessionStrategy));
return sessionAuthenticationStrategy;
}

/**
* 注册并发Session Filter
*/
@Bean
public ConcurrentSessionFilter concurrentSessionFilter() {
return new ConcurrentSessionFilter(sessionRegistry(), "/login?expired");
}

/**
* Rest 登陆成功后的处理
*/
public class RestAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws ServletException, IOException {
HttpUtil.responseOutWithJson(request,response, ApiResult.ok(authentication.getPrincipal()));
clearAuthenticationAttributes(request);
}
}

/**
* Rest 登录认证失败后的处理
*/

public class RestAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Override
public void onAuthenticationFailure (HttpServletRequest request, HttpServletResponse response, AuthenticationException exception)
throws ServletException, IOException {

logger.error("登录失败 exception={}" ,exception);
saveException(request, exception);
//密码错误
if(exception instanceof BadCredentialsException){
HttpUtil.responseOutWithJson(request,response, ApiResult.error(CmsWebApiCode.PASSWORD_ERROR));
}
//查询用户出错
else if(exception instanceof UsernameNotFoundException){
HttpUtil.responseOutWithJson(request,response, ApiResult.error(CmsWebApiCode.USERNAME_PASSWORD_ERROR));
}
//查询用户出错
else if(exception instanceof SessionAuthenticationException){
HttpUtil.responseOutWithJson(request,response, ApiResult.error(CmsWebApiCode.MAX_COUNT_SESSION_ERROR));
}
else {
HttpUtil.responseOutWithJson(request,response, ApiResult.error(CmsWebApiCode.AUTHORIZED_FAILD));
}
}
}

/**
* Rest 登出成功后的处理
*/

public class RestLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
logger.info("登出成功! ");
if (!StringUtils.isEmpty(request.getRequestedSessionId())){
//sessionRegistry().removeSessionInformation(request.getRequestedSessionId());
if(null!=authentication && null!=authentication.getDetails() && null!=authentication.getPrincipal()){
List<SessionInformation> sessionInformations= sessionRegistry().getAllSessions(authentication.getPrincipal(),false);
for (SessionInformation sessionInformation : sessionInformations) {
sessionInformation.expireNow();
}
sessionRegistry().getAllPrincipals().remove(authentication.getDetails());
}
}
HttpUtil.delCookies(request,response,"JSESSIONID", "X-XSRF-TOKEN");
HttpUtil.responseOk(request,response);

}
}

/**
* Rest 权限不通过的处理
*/
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {
//原生返回 response.sendError(HttpServletResponse.SC_UNAUTHORIZED,"Authentication Failed: " + authException.getMessage());
//cookie失效
if(authException instanceof InsufficientAuthenticationException){
HttpUtil.responseOutWithJson(request,response, ApiResult.error(CmsWebApiCode.INVALID_COOKIE));
}
HttpUtil.responseApiCode(request,response, ApiCode.ACCESS_DENIED);
}
}
}
http://git.oschina.net/xiangxik/castle-platform/blob/master/castle-sample/castle-sample-console/src/main/java/com/whenling/sample/security/MainWebSecurityConfigBean.java

@Configuration @Order(Ordered.HIGHEST_PRECEDENCE) publicclassMainWebSecurityConfigBeanextendsWebSecurityConfigurerAdapter{ @Value("${security.skip_auth_urls?:/assets/**,/captcha**,/upload/**}") privateString[]skipAuthUrls; @Autowired privateObjectFactoryobjectMapper; @Autowired privateObjectFactorymessageSourceAccessor; publicMainWebSecurityConfigBean(){ super(true); } @Override protectedvoidconfigure(HttpSecurityhttp)throwsException{ http.csrf().and().addFilter(newWebAsyncManagerIntegrationFilter()).exceptionHandling().and().headers().and().sessionManagement().and() .securityContext().and().requestCache().and().anonymous().and().servletApi().and().logout(); http.getSharedObject(AuthenticationManagerBuilder.class)// .authenticationProvider(null) .authenticationEventPublisher(defaultAuthenticationEventPublisher()); http.rememberMe().userDetailsService(userDetailsService()); FormLoginConfigurerconfigurer=http.headers().frameOptions().sameOrigin().and().csrf().disable().formLogin(); configurer.successHandler(newResultAuthenticationSuccessHandler(objectMapper.getObject())) .failureHandler(newResultAuthenticationFailureHanlder(objectMapper.getObject(),messageSourceAccessor.getObject())); ExceptionHandlingConfigurerexceptionConfigurer=configurer.permitAll().and().authorizeRequests().antMatchers(skipAuthUrls) .permitAll().anyRequest().authenticated().and().exceptionHandling(); exceptionConfigurer.authenticationEntryPoint( newExceptionAuthenticationEntryPoint(newHttp403ForbiddenEntryPoint(),newLoginUrlAuthenticationEntryPoint("/login"))); exceptionConfigurer.and().logout().logoutSuccessUrl("/login").permitAll(); } @Bean publicUserDetailsServiceuserDetailsService(){ returnnewAdminDetailsService(); } @Bean publicDefaultAuthenticationEventPublisherdefaultAuthenticationEventPublisher(){ returnnewDefaultAuthenticationEventPublisher(); } }
posted @ 2017-06-08 17:02  托马斯布莱克  阅读(223)  评论(0编辑  收藏  举报