java - Spring Boot 1.5 sessionRegistry().getAllPrincipals() 总是返回空列表
问题描述
我继承了一个 Spring Boot 1.5 项目,该项目目前无法向上迁移,需要使用会话注册表来管理用户(例如:列出登录用户、生产更新的电子邮件用户等)
我尝试了所有我能找到的现有 SO 解决方案,但它们都为 sessionRegistry().getAllPrincipals() 提供了一个空结果。我的安全配置如下所示:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.httpBasic().disable()
.formLogin().disable()
.headers().frameOptions().sameOrigin()
.and()
.sessionManagement().maximumSessions(1).sessionRegistry(sessionRegistry());
}
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
@Bean
public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
return new ServletListenerRegistrationBean<>(new HttpSessionEventPublisher());
}
}
我的应用程序配置如下所示:
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600000)
@EnableDiscoveryClient
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
@EnableZuulProxy
@EnableFeignClients
@EnableSwagger2
@SpringBootApplication
@RibbonClients({
@RibbonClient(name = "employeeService", configuration = StickySessionEditorRibbonConfiguration.class)
})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public PreFilter preFilter() {
return new PreFilter();
}
@Bean
public PostFilter postFilter() {
return new PostFilter();
}
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("JSESSIONID");
serializer.setCookiePath("/");
serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$");
serializer.setCookieMaxAge(3600000);
return serializer;
}
}
访问会话注册表的相关代码如下所示:
public class TestController extends BaseController {
@Autowired
private SessionRegistry sessionRegistry;
...
public List<User> findAllLoggedInUsers() {
final List<Object> allPrincipals = sessionRegistry.getAllPrincipals();
}
}
使用执行器/bean 端点,我可以看到 SessionRegistry Bean 处于活动状态。
我从几个浏览器成功登录,但登录前后 allPrincipals 的大小始终为 0。
我不知道为什么,非常感谢这里的任何帮助。
基于@M.Deinum 关于禁用登录的评论,我想补充一点,该项目使用 Zuul 过滤器(preFilter 和 PostFilter),如应用程序配置中所示。我们有一个与这个 api-gateway 服务完全不同的 account-manager 服务,它基于简单的登录名/密码对用户进行身份验证。preFilter 中的逻辑如下所示:
public class PreFilter extends BaseFilter {
@Autowired
SessionRegistry sessionRegistry;
@Autowired
private SessionRepository sessionRepository;
@Override
public String filterType() {
return "pre";
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest req = ctx.getRequest();
HttpSession session = req.getSession();
try {
String uri = req.getRequestURI();
// user assumed is not authenticated
String authToken = null;
//Login code
if (uri.contains("/api/public/authorization/login") && req.getMethod().equals("POST")) {
session.removeAttribute(AUTH_TOKEN_HEADER);
LoginRequest request = createLoginRequest(req);
/* LoginRequest basically contains "userName" and "password" entered by user */
ResponseEntity<MessageWrapper<String>> response = accountManagerFeignClient.authenticate(loginRequest);
authToken = response.getBody().getData();
if (authToken != null) {
session.setAttribute(AUTH_TOKEN_HEADER, authToken);
ctx.setResponseStatusCode(HttpStatus.OK.value());
ctx.setSendZuulResponse(false);
return null;
}
// authToken == null implies the user was not authenticated by accountManager
} else if ("internal or public apis are called, they won't need authentication") {
// user remains unauthenticated, which is fine for public or internal apis
return null;
} else {
// Assume this is a protected API and provide authToken if one exists
authToken = (String) session.getAttribute(AUTH_TOKEN_HEADER);
}
if (authToken == null)
throw new Exception(UNAUTHORIZED + ". Log String: " + logString);
// Validated user will go through here
ctx.addZuulRequestHeader(AUTH_TOKEN_HEADER, authToken);
} catch (Exception ex) {
ctx.setResponseBody(UNAUTHORIZED);
ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
ctx.setSendZuulResponse(false);
}
return null;
} }
postFilter 中唯一相关的逻辑(类似于 preFilter)以这种方式在注销期间禁用会话:
if (authToken != null) {
session.removeAttribute(AUTH_TOKEN_HEADER);
session.removeAttribute(StickySessionEditorRule.STICKY_ID);
session.removeAttribute(StickySessionWSGRule.STICKY_ID);
ctx.setResponseBody(LOGGED_OUT);
ctx.setResponseStatusCode(HttpStatus.OK.value());
ctx.setSendZuulResponse(false);
}
session.invalidate();
我的另一个耗时的选择是使用 HTTPSessionBindingListener ,如此处所示。我还没有尝试过。
最后,如果上述方法都不起作用,我怎么能直接使用 redis 并执行 findAll() ?看起来有一个 SessionRepository,但我找不到使用它的文档化方式。
谢谢你。
解决方案
推荐阅读
- c# - 删除 datagridview 标题中的排序箭头并将文本放在框的中心
- java - 在文本的下一行和中心设置图像跨度
- c# - 在 SQL 表中使用 Html 并在 foreach 语句中检索它
- authentication - 过期时间在 ASP.Net Core 中不起作用
- c# - 如何在 Blob 存储中创建文件夹
- python - 在 sklearn RandomForestClassifier 中移动假想的决策边界
- google-tag-manager - dataLayer 变量在 GTM 自定义 HTML 标记内没有动态变化
- github - 有什么方法可以在没有第三方服务器的情况下,在新问题出现时自动构建 GitHub 页面?
- facebook - 使用 Facebook 评论社交插件 - 新创建页面的许多不相关评论
- caching - 什么是间接费用百分比?