我在我的应用中使用spring security。在那我必须使用自定义令牌(存储在与用户映射的数据库中)来保护REST API。
这是我的网络安全配置。
@Autowired
public DataSource dataSource;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource)
.passwordEncoder(passwordEncoder())
.usersByUsernameQuery(getUserQuery()).authoritiesByUsernameQuery(getAuthoritiesQuery());
}
以上代码是我的全局身份验证配置。
@Configuration
protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserRoleManager userRolePage;
@Override
protected void configure(HttpSecurity http) throws Exception
{
List<RolePageMap> rolePageMaps = userRolePage.getRolePageMapList();
for (RolePageMap rolePageMap : rolePageMaps) {
http.authorizeRequests()
.antMatchers(rolePageMap.getAccessablePages().getPageValue())
.access("hasRole('" + rolePageMap.getUserRole().getRoleName() + "')");
}
http.authorizeRequests().and().formLogin()
.usernameParameter("username").passwordParameter("password")
.and().logout().logoutSuccessUrl("/")
.and().exceptionHandling().accessDeniedPage("/successMessage.html")
.and().csrf().csrfTokenRepository(csrfTokenRepository()).and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)
.addFilterBefore(customAuthFilter(), UsernamePasswordAuthenticationFilter.class);
}
private Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
final String customToken = request.getHeader(AUTH_HEADER_NAME);
if (csrf != null && customToken == null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null || token != null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
};
}
private Filter customAuthFilter() {
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
final String token = request.getHeader(AUTH_HEADER_NAME);
if(token != null) {
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken("admin", "admin");
SecurityContextHolder.getContext().setAuthentication(authToken);
}
filterChain.doFilter(request, response);
}
};
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
}
注意:在上面的代码中,我在同一安全配置中使用了两个过滤器。
该配置的意图是,如果自定义令牌存在于头文件中,我们应该使用相应的过滤器,如果请求中没有,那么它应该验证CSRF令牌。
这里的问题是如果自定义存在,那么它是有效的,当我删除标题并再次调用API时,它会返回结果但不应该。
这是实现此安全性的正确方法吗?
有人可以帮我吗?