我试图将对dashboard.html
页面的访问权限限制为未经身份验证的用户。到目前为止,我没有成功。这是我的WebSecurityConfigurerAdapter
:
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAuthenticationSuccessHandler authenticationSuccessHandler;
@Autowired
private CustomAuthenticationFailureHandler authenticationFailureHandler;
@Autowired
private CustomUserDetailsService userDetailsService;
@Autowired
private TokenAuthenticationService tokenAuthenticationService;
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder builder) throws Exception {
builder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/index.html", "/",
"/login.html","/signup.html", "/videos/**",
"/login", "/logout", "/images/**", "/fonts/**",
"/css/**", "/js/**", "/pages/**", "/sass/**"
).permitAll()
.and()
.authorizeRequests()
.antMatchers("/dashboard/**", "/dashboard.html/**").authenticated()
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.addFilterBefore(new StatelessLoginFilter("/login", tokenAuthenticationService, userDetailsService, authenticationManager()), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService), UsernamePasswordAuthenticationFilter.class)
.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/login")
.usernameParameter("email")
.passwordParameter("password")
.successHandler(authenticationSuccessHandler)
.failureHandler(authenticationFailureHandler)
.and()
.logout()
.logoutSuccessUrl("/")
.deleteCookies("JSESSIONID")
.permitAll()
.and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.addFilterAfter(new CsrfTokenFilter(), CsrfFilter.class);
}
}
每当我设置这种方式时,每当我尝试登录时,都会导致无限重定向循环。浏览器尝试导航到dashboard.html
但受限制。这会导致重定向到登录页面,登录页面会尝试重定向到仪表板,因为有一个有效的令牌。
如果我将其设置如下,则每个人都可以访问dashboard.html
并拨打/dashboard
端点,这是不需要的:
http
.authorizeRequests()
.antMatchers("/index.html", "/",
"/login.html","/signup.html", "/videos/**",
"/login", "/logout", "/images/**", "/fonts/**",
"/css/**", "/js/**", "/pages/**", "/sass/**",
"/dashboard/**", "/dashboard.html/**").permitAll()
.and()
.authorizeRequests()
.anyRequest().authenticated()
我的登录使用JWT令牌并使用下面的过滤器设置SecurityContext
占位符:
class StatelessLoginFilter extends AbstractAuthenticationProcessingFilter {
private final TokenAuthenticationService tokenAuthenticationService;
private final CustomUserDetailsService userDetailsService;
protected StatelessLoginFilter(String urlMapping, TokenAuthenticationService tokenAuthenticationService,
CustomUserDetailsService userDetailsService, AuthenticationManager authManager) {
super(new AntPathRequestMatcher(urlMapping));
this.userDetailsService = userDetailsService;
this.tokenAuthenticationService = tokenAuthenticationService;
setAuthenticationManager(authManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
final BusinessUser user = new ObjectMapper().readValue(request.getInputStream(), BusinessUser.class);
final UsernamePasswordAuthenticationToken loginToken = new UsernamePasswordAuthenticationToken(
user.getEmail(), user.getPassword());
return getAuthenticationManager().authenticate(loginToken);
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
FilterChain chain, Authentication authentication) throws IOException, ServletException {
final BusinessUser authenticatedUser = userDetailsService.loadUserByUsername(authentication.getName());
final UserAuthentication userAuthentication = new UserAuthentication(authenticatedUser);
tokenAuthenticationService.addAuthentication(response, userAuthentication);
SecurityContextHolder.getContext().setAuthentication(userAuthentication);
}
我使用行SecurityContextHolder.getContext().setAuthentication(userAuthentication);
来设置身份验证。这完全没问题。如果在匹配从用户发送的凭证的DB中找到用户,则安全上下文可用于检索与用户相关联的各种数据。
我的问题:如何限制页面dashboard.html
并将/dashboard
端点调用给未经身份验证的用户(SecurityContextHolder
内没有身份验证对象的用户)?
答案 0 :(得分:3)
您可以将自定义RequestMatcher
与denyAll
结合使用。首先,您的自定义匹配器:
public class PermittedPagesMatcher implements RequestMatcher {
@Override
public boolean matches(HttpServletRequest httpServletRequest) {
if (matchesToPaths(httpServletRequest,"/index.html", "/", "/login.html","/signup.html", "/videos/**", "/login", "/logout", "/images/**", "/fonts/**", "/css/**", "/js/**", "/pages/**", "/sass/**", "/dashboard/**", "/dashboard.html/**")) {
return true;
}
if (matchesToPaths(httpServletRequest, "/dashboard/**", "/dashboard.html/**")) {
return httpServletRequest.getUserPrincipal() == null;
}
return false;
}
private boolean matchesToPaths(HttpServletRequest httpServletRequest, String... paths) {
for (String p : paths) {
if (new AntPathRequestMatcher(p).matches(httpServletRequest)) {
return true;
}
}
return false;
}
}
此自定义RequestMatcher
会将您的请求过滤到所有默认页面的允许页面,并且仅当请求未经过身份验证时才可使用仪表板。
其次,结合匹配器和denyAll()
http
.authorizeRequests()
.requestMatchers(new PermittedPagesMatcher())
.permitAll()
.and()
.antMatchers("/dashboard/**", "/dashboard.html/**")
.denyAll()
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
denyAll()
确保默认情况下不允许任何人访问此页面。
注意:许可和拒绝的顺序很重要!