Java Spring引导,具有用于单点登录的只读会话
我们有一个遗留的Spring应用程序a,它不使用Spring引导来处理身份验证,并使用Spring会话将会话写入Redis。Redis中的数据存储为XML 我们现在想引入一个新的应用程序B,使用spring boot 2.2.6.RELEASE和spring session Corn-RC1,如果用户已使用角色_ADMIN登录,该应用程序应该可以使用。也就是说,这可以被视为一种非常粗糙的单点登录方式。用户永远不应该能够在B中进行身份验证。如果可能的话,如果要禁用身份验证,它应该只检查现有用户是否在会话存储库redis中进行了身份验证,并且具有角色\u ADMIN。A和B都位于同一个域下,因此浏览器将传播cookie。我尝试了各种不同的方法来实现这一点,例如: @配置 @启用Web安全性 类服务BStringSecurityConfig:WebSecurityConfigureAdapter{ @自动连线 趣味配置GlobalAuth:AuthenticationManagerBuilder{ auth.inMemoryAuthentication } 覆盖配置HTTP:HttpSecurity{ http .批准请求 .anyRequest.hasRoleADMIN 和 .formLogin 和 .httpBasic.disable } } 但这将显示默认登录屏幕: 我还尝试完全删除此部分:Java Spring引导,具有用于单点登录的只读会话,java,spring-boot,spring-security,single-sign-on,spring-session,Java,Spring Boot,Spring Security,Single Sign On,Spring Session,我们有一个遗留的Spring应用程序a,它不使用Spring引导来处理身份验证,并使用Spring会话将会话写入Redis。Redis中的数据存储为XML 我们现在想引入一个新的应用程序B,使用spring boot 2.2.6.RELEASE和spring session Corn-RC1,如果用户已使用角色_ADMIN登录,该应用程序应该可以使用。也就是说,这可以被视为一种非常粗糙的单点登录方式。用户永远不应该能够在B中进行身份验证。如果可能的话,如果要禁用身份验证,它应该只检查现有用户是否
@Autowired
fun configureGlobal(auth: AuthenticationManagerBuilder) {
auth.inMemoryAuthentication()
}
但是它会生成一个默认的用户和密码,并且它似乎不会调用configure方法,或者不管怎样,配置都不起作用
如何解决这个问题?您需要的是在应用程序B上禁用formLogin和httBasic,并在spring的身份验证过滤器AnonymousAuthenticationFilter或UsernamePasswordAuthenticationFilter之前添加一个过滤器。在自定义过滤器中,您将从请求对象中提取cookie/头/令牌,并基于此,访问redis缓存以获取会话详细信息。然后,此筛选器将验证会话并创建类型为org.springframework.security.core.Authentication的对象,并在当前SpringSecurityContext中设置该对象 下面是这方面的sudo代码 ServiceBStringSecurityConfig 作者点 AuthTokenFilter
如前所述,这是sudo代码,因此可能需要进行一些调整。然而,基于令牌的身份验证的一般要点保持不变 只是澄清一下,您希望登录页面仅在用户尝试访问应用程序A时显示。如果他们尝试在没有任何形式的身份验证的情况下访问应用程序B,则不应将其重定向到登录页面?如果用户被重定向到应用程序A的登录页面,则无所谓,但这将是一个很好的奖励:从不在B上显示登录页面是我追求的。
@Configuration
@EnableWebSecurity
public class ServiceBSpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(authEntryPoint()).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.httpBasic().disabled().and()
.formLogin().disabled().and()
.authorizeRequests().anyRequest().hasRole("ADMIN")
http.addFilterBefore(authTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
public AuthTokenFilter authTokenFilter() {
return new AuthTokenFilter();
}
@Bean
public AuthEntryPoint authEntryPoint() {
return new AuthEntryPoint()
}
}
public class AuthEntryPoint implements AuthenticationEntryPoint {
private static final Logger logger = LoggerFactory.getLogger(AuthEntryPoint.class);
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
// Very generic authEntryPoint which simply returns unauthorized
// Could implement additional functionality of forwarding the Application A login-page
logger.error("Unauthorized error: {}", authException.getMessage());
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error: Unauthorized");
}
}
public class AuthTokenFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// extract some sort of token or cookie value from request
token = request.getHeader("Token");
if (token != null) {
// Validate the token by retrieving session from redis cache
// Create org.springframework.security.core.Authentication from the token
Authentication auth = authFactory.getAuthentication(token);
// Set the spring security context with the auth
SecurityContextHolder.getContext().setAuthentication(auth);
} else {
// Do something if token not present at all
}
// Continue to to filter chain
filterChain.doFilter(request, response);
}
}