2016-11-12 43 views
1

我试图限制对未经身份验证的用户访问名为dashboard.html的页面。到目前为止,我没有成功。这里是我WebSecurityConfigurerAdapter如何使用Spring Boot REST限制对.html页面的访问

@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);设置认证。这工作非常好。如果在数据库中找到与用户发送的凭证相匹配的用户,则安全上下文可用于检索与用户关联的各种数据。

我的问题:我怎样才能限制dashboard.html页面并调用到/dashboard端点未经验证的用户(那些没有SecurityContextHolder内的认证对象)?

+0

你确定要给“/”允许所有,可能是因为它允许所有的 – kuhajeyan

回答

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()确保,在默认情况下没有人被允许访问此页面。

注意事项:许可证和拒绝的顺序很重要!

+0

我想不能在未经认证的情况下访问它。有了这个设置,即使我没有身份验证令牌,我仍然可以访问它。我将return语句修改为:'return httpServletRequest.getUserPrincipal()!= null;',因为只有存在经过身份验证的用户时它才会返回true。现在我遇到了同样的问题。现在没有人可以访问'dashboard.html'。即使他们被认证。我只想验证/登录的用户能够访问dashboard.html。我只能让所有人访问它,或者现在没有人访问它。 –

+0

我很困惑...... Quote:_如何限制对未经身份验证的用户的调用._如果只想允许经过身份验证的用户,请移除'“/ dashboard/**”'和你的原始代码的'http.authorizeRequests()。antMatchers(....)'''/dashboard.html/**'',你很好。 – Schrieveslaach

+0

虽然我的原始设置有问题。出于某种原因,无论我是否通过身份验证,我都无法访问带有该设置的'/ dashboard.html'。我甚至打印出'httpServletRequest.getUserPrincipal()!= null;'的值,并且它返回true。所以这意味着有一个经过验证的用户,但由于某种原因,我无法访问'/ dashboard.html'。 –