【发布时间】:2022-09-23 03:53:20
【问题描述】:
我正在尝试使用 Spring Security 实现 RBAC。用户认证单独实现,并生成sessionId 供应用使用。我想让 Spring Security 从 Http Header 中获取 sessionId 并使用 sessionId 从数据库中获取权限,以确定用户是否有权访问某些端点。问题是我不知道如何按需从数据库中获取权限,也不知道配置是否正确。这是我到目前为止所拥有的:
@Configuration
@EnableWebSecurity
public class CustomSecurityFilter {
@Bean
AuthenticationManager customAuthenticationManager(HttpHeaderAuthenticationProvider httpHeaderAuthenticationProvider) {
return new ProviderManager(List.of(httpHeaderAuthenticationProvider));
}
@Bean
HttpHeaderAuthenticationProvider newHttpHeaderAuthenticationProvider() {
return new HttpHeaderAuthenticationProvider();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http,
AuthenticationManager authenticationManager) throws Exception {
http.addFilterBefore(getFilter(authenticationManager), AnonymousAuthenticationFilter.class).authorizeRequests()
.antMatchers(HttpMethod.GET, \"/api/apples\").hasAuthority(\"viewApples\")
.antMatchers(HttpMethod.POST, \"/api/apples\").hasAuthority(\"createApples\")
return http.build();
}
private Filter getFilter(AuthenticationManager authenticationManager) {
return new HttpHeaderProcessingFilter(
new OrRequestMatcher(
new AntPathRequestMatcher(\"/api/apples/**\"),
),
authenticationManager
);
}
}
public class HttpHeaderAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
var sessionId = ((String) authentication.getPrincipal());
// Somehow connect to database to get session and authorities information?
boolean isValid = sessionId != null;
if (isValid) {
return newPreAuthenticatedToken(\"sessionId\", List.of());
} else {
throw new AccessDeniedException(\"Invalid sessionId\");
}
}
@Override
public boolean supports(Class<?> authentication) {
return PreAuthenticatedAuthenticationToken.class.equals(authentication);
}
public static PreAuthenticatedAuthenticationToken newPreAuthenticatedToken(String userId, List<String> permissions) {
var grantedAuthorityList = new ArrayList<GrantedAuthority>();
for (String permission : permissions) {
grantedAuthorityList.add(new SimpleGrantedAuthority(permission));
}
return new PreAuthenticatedAuthenticationToken(userId, null, grantedAuthorityList);
}
}
public class HttpHeaderProcessingFilter extends AbstractAuthenticationProcessingFilter {
public HttpHeaderProcessingFilter(RequestMatcher requiresAuthenticationRequestMatcher,
AuthenticationManager authenticationManager) {
super(requiresAuthenticationRequestMatcher);
setAuthenticationManager(authenticationManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
return getAuthenticationManager().authenticate(
// Not sure if we are supposed to do this
HttpHeaderAuthenticationProvider.newPreAuthenticatedToken(\"sessionId\", List.of())
);
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException {
SecurityContextHolder.getContext().setAuthentication(authResult);
chain.doFilter(request, response);
}
}
我尝试使用这些资源:
- https://salahuddin-s.medium.com/custom-header-based-authentication-using-spring-security-17f4163d0986
- https://www.baeldung.com/spring-security-granted-authority-vs-role
我还想知道 JWT 是否是一个很好的候选者,可以用来代替带有 RBAC + 会话处理的自定义 sessionId。
标签: spring spring-boot spring-security