基于自定义HTTP Header的Spring Security权限过滤实现疑问
Spring Security RBAC实现问题及JWT替代疑问
问题描述
我正尝试用Spring Security实现RBAC(基于角色的访问控制)。用户认证已经单独实现,系统会生成sessionId供应用使用。我希望Spring Security从HTTP Header中获取sessionId,再通过这个sessionId从数据库获取权限信息,以此判断用户是否有权访问特定端点。当前问题是:我不知道如何按需从数据库获取权限,也不确定现有配置是否正确。
现有实现代码
CustomSecurityFilter配置类
@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 ); } }
HttpHeaderAuthenticationProvider类
public class HttpHeaderAuthenticationProvider implements AuthenticationProvider { @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { var sessionId = ((String) authentication.getPrincipal()); // 不知道怎么连接数据库获取session和权限信息? 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); } }
HttpHeaderProcessingFilter类
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( // 不确定这么做是否正确 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); } }
额外疑问
另外我还想了解,用JWT替代自定义sessionId来实现RBAC+会话处理是否合适?
内容的提问来源于stack exchange,提问作者superflux
相关产品推荐
相关产品推荐

