Spring 安全,正在更新 SecurityContextHolder
Spring Security, updating SecurityContextHolder
我有一个多租户环境,一个数据库,每个租户都有单独的模式。
在用户登录时,我加载了默认租户,一切正常。我创建了 switchTenant 方法,该方法应该将当前租户(默认租户)与选定的租户切换。我有部分工作的解决方案,我将该信息保存在 HttpSession 中。一切正常,但有一些副作用,例如:tomcat 重新启动用户需要重新登录,或 android 用户在应用程序关闭时失去会话。
正在尝试寻找更好的解决方案来替换 HttpSession,将当前租户信息存储在 SecurityContext 中。当然我失败了,这就是为什么我向你们寻求帮助的原因。
这是我正在尝试使其工作的相关代码:
TenantInterceptor(这里一切正常)
...
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
String schema = SecurityUtils.getCurrentSchema().orElse("");
if (schema.equals("")) {
TenantContext.setCurrentTenant("public");
} else {
TenantContext.setCurrentTenant(schema);
}
return true;
}
...
SecurityUtils 助手class(这里也一切正常)
...
public static Optional<String> getCurrentSchema() {
SecurityContext securityContext = SecurityContextHolder.getContext();
return Optional.ofNullable(securityContext.getAuthentication()).map(authentication -> {
if (authentication.getPrincipal() instanceof TenantUser) {
TenantUser springSecurityUser = (TenantUser) authentication.getPrincipal();
return springSecurityUser.getCurrentSchema();
}
return null;
});
}
...
服务 class(我需要修复)
...
public void switchTenant(Tenant tenant) {
Optional<TenantDTO> tenantExist = this.findAllUserTenants().stream()
.filter(t -> t.getName().equals(tenant.getName())).findFirst();
if (tenantExist.isPresent()) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Authentication newAuth = null;
if (auth.getClass() == UsernamePasswordAuthenticationToken.class) {
TenantUser principal = (TenantUser) auth.getPrincipal();
principal.setCurrentSchema(tenant.getSchema());
newAuth = new UsernamePasswordAuthenticationToken(principal, auth.getCredentials(), auth.getAuthorities());
}
SecurityContextHolder.getContext().setAuthentication(newAuth);
...
租户用户class
public class TenantUser extends org.springframework.security.core.userdetails.User {
private String userId;
private String currentSchema;
public TenantUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
super(username, password, authorities);
}
...
无论如何,这行代码:SecurityContextHolder.getContext().setAuthentication(newAuth); 总是给我旧的身份验证,而不是更新当前租户架构的身份验证
感谢您的帮助。
方法不好。因为我使用 jwt 令牌进行身份验证,所以最好的方法是将当前租户模式存储到令牌中。
在租户切换时,我使用新的当前模式刷新令牌并将其发送回客户端。
我有一个多租户环境,一个数据库,每个租户都有单独的模式。
在用户登录时,我加载了默认租户,一切正常。我创建了 switchTenant 方法,该方法应该将当前租户(默认租户)与选定的租户切换。我有部分工作的解决方案,我将该信息保存在 HttpSession 中。一切正常,但有一些副作用,例如:tomcat 重新启动用户需要重新登录,或 android 用户在应用程序关闭时失去会话。
正在尝试寻找更好的解决方案来替换 HttpSession,将当前租户信息存储在 SecurityContext 中。当然我失败了,这就是为什么我向你们寻求帮助的原因。
这是我正在尝试使其工作的相关代码:
TenantInterceptor(这里一切正常)
...
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
String schema = SecurityUtils.getCurrentSchema().orElse("");
if (schema.equals("")) {
TenantContext.setCurrentTenant("public");
} else {
TenantContext.setCurrentTenant(schema);
}
return true;
}
...
SecurityUtils 助手class(这里也一切正常)
...
public static Optional<String> getCurrentSchema() {
SecurityContext securityContext = SecurityContextHolder.getContext();
return Optional.ofNullable(securityContext.getAuthentication()).map(authentication -> {
if (authentication.getPrincipal() instanceof TenantUser) {
TenantUser springSecurityUser = (TenantUser) authentication.getPrincipal();
return springSecurityUser.getCurrentSchema();
}
return null;
});
}
...
服务 class(我需要修复)
...
public void switchTenant(Tenant tenant) {
Optional<TenantDTO> tenantExist = this.findAllUserTenants().stream()
.filter(t -> t.getName().equals(tenant.getName())).findFirst();
if (tenantExist.isPresent()) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Authentication newAuth = null;
if (auth.getClass() == UsernamePasswordAuthenticationToken.class) {
TenantUser principal = (TenantUser) auth.getPrincipal();
principal.setCurrentSchema(tenant.getSchema());
newAuth = new UsernamePasswordAuthenticationToken(principal, auth.getCredentials(), auth.getAuthorities());
}
SecurityContextHolder.getContext().setAuthentication(newAuth);
...
租户用户class
public class TenantUser extends org.springframework.security.core.userdetails.User {
private String userId;
private String currentSchema;
public TenantUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
super(username, password, authorities);
}
...
无论如何,这行代码:SecurityContextHolder.getContext().setAuthentication(newAuth); 总是给我旧的身份验证,而不是更新当前租户架构的身份验证
感谢您的帮助。
方法不好。因为我使用 jwt 令牌进行身份验证,所以最好的方法是将当前租户模式存储到令牌中。 在租户切换时,我使用新的当前模式刷新令牌并将其发送回客户端。