我已将基本身份验证配置为Spring-Boot应用程序。一切都是Java Config,没有xml。
import org.springframework.context.annotation.Configuration;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// Authenticate username -> admin, password -> admin & set role as "ROLE_USER"
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
// All Requests should be Authenticated
.anyRequest().authenticated()
.and()
// Enable Basic Authentication
.httpBasic()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/main", true)
.loginProcessingUrl("/session")
.usernameParameter("Username").passwordParameter("Password")
.and()
.logout().logoutUrl("/logout").permitAll()
.and().csrf().disable();
}
}
它配置为基本身份验证和普通表单登录。当我在Firefox上测试Rest-Client的基本身份验证时,我可以访问安全URL“/ main”。但是在回复标题中,我得到Set-Cookie: JSESSIONID=301225C7AE7C74B0892887389996785D;
。
我不希望为基本身份验证生成Cookie。我希望真正Stateless session
进行基本身份验证。请注意,我需要为表单登录生成cookie才能工作,因此禁用cookie不是一种选择。我知道xml配置中的create-session="stateless"
,但有没有办法在Java配置中执行相同的操作,以便基本身份验证是无状态的,而表单身份验证是状态的。?
答案 0 :(得分:8)
I know about the create-session="stateless" in xml configuration, but is there any way to do the same in Java config so that Basic Authentication is Stateless and Form-Authentication is Statefull..?
您可以执行以下操作。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
对于您的问题,可以使用自定义Java Config。
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
@Inject
UserDetailsService userService;
@Bean
public AuthenticationManager authenticationManager() throws Exception {
AuthenticationManager authenticationManager = new ProviderManager(
Arrays.asList(authenticationProvider()));
return authenticationManager;
}
@Bean
public AuthenticationProvider authenticationProvider() throws Exception {
CustomAuthenticationProvider authenticationProvider = new CustomAuthenticationProvider();
authenticationProvider.setUserDetailsService(userService);
authenticationProvider.setSaltSource(saltSource());
authenticationProvider.setPasswordEncoder(passwordEncoder());
authenticationProvider.afterPropertiesSet();
return authenticationProvider;
}
@Bean
public SaltSource saltSource() throws Exception {
ReflectionSaltSource saltSource = new ReflectionSaltSource();
saltSource.setUserPropertyToUse("salt");
saltSource.afterPropertiesSet();
return saltSource;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new Md5PasswordEncoder();
}
@Bean
public FilterChainProxy springSecurityFilterChain()
throws ServletException, Exception {
List<SecurityFilterChain> securityFilterChains = new ArrayList<SecurityFilterChain>();
securityFilterChains.add(new DefaultSecurityFilterChain(
new AntPathRequestMatcher("/login**")));
securityFilterChains.add(new DefaultSecurityFilterChain(
new AntPathRequestMatcher("/resources/**")));
securityFilterChains.add(new DefaultSecurityFilterChain(
new AntPathRequestMatcher("/api/**"),
securityContextPersistenceFilterASCFalse(),
basicAuthenticationFilter(), exceptionTranslationFilter(),
filterSecurityInterceptor()));
securityFilterChains.add(new DefaultSecurityFilterChain(
new AntPathRequestMatcher("/**"),
securityContextPersistenceFilterASCTrue(), logoutFilter(),
usernamePasswordAuthenticationFilter(),
exceptionTranslationFilter(), filterSecurityInterceptor()));
return new FilterChainProxy(securityFilterChains);
}
@Bean
public SecurityContextPersistenceFilter securityContextPersistenceFilterASCTrue() {
return new SecurityContextPersistenceFilter(
new HttpSessionSecurityContextRepository());
}
@Bean
public SecurityContextPersistenceFilter securityContextPersistenceFilterASCFalse() {
HttpSessionSecurityContextRepository httpSessionSecurityContextRepository = new HttpSessionSecurityContextRepository();
httpSessionSecurityContextRepository.setAllowSessionCreation(false);
return new SecurityContextPersistenceFilter(
httpSessionSecurityContextRepository);
}
@Bean
public ExceptionTranslationFilter exceptionTranslationFilter() {
ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(
new LoginUrlAuthenticationEntryPoint("/login"));
AccessDeniedHandlerImpl accessDeniedHandlerImpl = new AccessDeniedHandlerImpl();
accessDeniedHandlerImpl.setErrorPage("/exception");
exceptionTranslationFilter
.setAccessDeniedHandler(accessDeniedHandlerImpl);
exceptionTranslationFilter.afterPropertiesSet();
return exceptionTranslationFilter;
}
@Bean
public UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter()
throws Exception {
UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter = new UsernamePasswordAuthenticationFilter();
usernamePasswordAuthenticationFilter
.setAuthenticationManager(authenticationManager());
usernamePasswordAuthenticationFilter.setAllowSessionCreation(true);
SimpleUrlAuthenticationSuccessHandler successHandler = new SimpleUrlAuthenticationSuccessHandler(
"/index");
successHandler.setAlwaysUseDefaultTargetUrl(true);
usernamePasswordAuthenticationFilter
.setAuthenticationSuccessHandler(successHandler);
usernamePasswordAuthenticationFilter
.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(
"/login?error=true"));
usernamePasswordAuthenticationFilter
.setAuthenticationDetailsSource(new CustomWebAuthenticationDetailsSource());
usernamePasswordAuthenticationFilter.afterPropertiesSet();
return usernamePasswordAuthenticationFilter;
}
@Bean
public FilterSecurityInterceptor filterSecurityInterceptor()
throws Exception {
FilterSecurityInterceptor filterSecurityInterceptor = new FilterSecurityInterceptor();
filterSecurityInterceptor
.setAuthenticationManager(authenticationManager());
filterSecurityInterceptor
.setAccessDecisionManager(accessDecisionManager());
filterSecurityInterceptor.setRunAsManager(runAsManager());
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();
List<ConfigAttribute> configs = new ArrayList<ConfigAttribute>();
configs.add(new org.springframework.security.access.SecurityConfig(
"isAuthenticated()"));
requestMap.put(new AntPathRequestMatcher("/**"), configs);
FilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource = new ExpressionBasedFilterInvocationSecurityMetadataSource(
requestMap, new DefaultWebSecurityExpressionHandler());
filterSecurityInterceptor
.setSecurityMetadataSource(filterInvocationSecurityMetadataSource);
filterSecurityInterceptor.afterPropertiesSet();
return filterSecurityInterceptor;
}
public AffirmativeBased accessDecisionManager() throws Exception {
List<AccessDecisionVoter> voters = new ArrayList<AccessDecisionVoter>();
voters.add(new WebExpressionVoter());
voters.add(new RoleVoter());
AffirmativeBased affirmativeBased = new AffirmativeBased(voters);
affirmativeBased.setAllowIfAllAbstainDecisions(false);
affirmativeBased.afterPropertiesSet();
return affirmativeBased;
}
@Bean
public RunAsManager runAsManager() throws Exception {
RunAsManagerImpl runAsManager = new RunAsManagerImpl();
runAsManager.setKey("V_RUN_AS");
runAsManager.afterPropertiesSet();
return runAsManager;
}
@Bean
public LogoutFilter logoutFilter() throws ServletException {
List<LogoutHandler> handlers = new ArrayList<LogoutHandler>();
handlers.add(new CookieClearingLogoutHandler("JSESSIONID"));
handlers.add(new SecurityContextLogoutHandler());
LogoutFilter logoutFilter = new LogoutFilter("/login",
handlers.toArray(new LogoutHandler[] {}));
logoutFilter.afterPropertiesSet();
return logoutFilter;
}
@Bean
public RequestContextFilter requestContextFilter() {
return new RequestContextFilter();
}
@Bean
public BasicAuthenticationFilter basicAuthenticationFilter()
throws Exception {
BasicAuthenticationEntryPoint basicAuthenticationEntryPoint = new BasicAuthenticationEntryPoint();
basicAuthenticationEntryPoint.setRealmName("V_REALM");
basicAuthenticationEntryPoint.afterPropertiesSet();
BasicAuthenticationFilter basicAuthenticationFilter = new BasicAuthenticationFilter(
authenticationManager(), basicAuthenticationEntryPoint);
basicAuthenticationFilter
.setAuthenticationDetailsSource(new CustomWebAuthenticationDetailsSource());
basicAuthenticationFilter.afterPropertiesSet();
return basicAuthenticationFilter;
}
}
此配置创建两种不同的身份验证机制。
对于以/api/*
开头的任何请求,它将使用basicAuthenticationFilter
和securityContextPersistenceFilterASCFalse
会话创建为假。
对于以/*
开头的任何请求,它将使用usernamePasswordAuthenticationFilter
和securityContextPersistenceFilterASCTrue
会话创建为真。
您可以使用此功能并对其进行更改以解决您的问题。
答案 1 :(得分:0)
对于遇到此问题的其他人,请点击此处查看其他内容。
我使用Spring Boot遇到同样的问题,甚至用
sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
我仍然看到设置了JSESSIONID Cookie。在我的情况下(使用JWT),缺少的部分似乎是在HttpSessionSecurityContextRepository
对象上设置setAllowSessionCreation,如下所示:
public class StatelessAuthenticationFilter extends GenericFilterBean {
private final MyTokenAuthService authenticationService;
private SecurityContextRepository repository = new HttpSessionSecurityContextRepository();
protected final Logger logger = LoggerFactory.getLogger(getClass().getName());
public StatelessAuthenticationFilter(MyTokenAuthService authenticationService) {
this.authenticationService = authenticationService;
((HttpSessionSecurityContextRepository) repository).setAllowSessionCreation(false);
}
}
我指出这是HttpSessionSecurityContextRepository
中的这些行:
private boolean allowSessionCreation = true;