繁体   English   中英

尝试访问spring security中的登录页面时访问被拒绝的异常

[英]Access denied exception while trying to access the login page in spring security

我正在使用基于java的spring security。 我创建了自定义访问决策选民impl。

但是当我运行应用程序时,我无法打开登录页面,因为它说,访问被拒绝。

这是在我添加自定义访问决策选民impl之后发生的。 我想问题是由于自定义AccessDecisionVoter中的以下代码。

if(authentication instanceof AnonymousAuthenticationToken)
            return ACCESS_DENIED;

但我需要这样,以便不检查未登录用户的权限。

它进入无限循环,登录页面,访问决策选民,访问被拒绝,登录页面等。

下面是spring安全配置代码。

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private AffirmativeBased accessDecisionManager;

    @Bean
    @Autowired
    public AffirmativeBased accessDecisionManager(AccessDecisionVoterImpl accessDecisionVoter) {
        List<AccessDecisionVoter<?>> accessDecisionVoters = new ArrayList<AccessDecisionVoter<?>>();
        accessDecisionVoters.add(accessDecisionVoter);
        AffirmativeBased accessDecisionManager = new AffirmativeBased(accessDecisionVoters);
        return accessDecisionManager;
    }

    @Override
    @Autowired
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        PasswordEncoder passwordEncoder = new PasswordEncoder();
        passwordEncoder.setStringDigester(stringDigester());
        return passwordEncoder;
    }

    @Bean
    public PooledStringDigester stringDigester() {
        PooledStringDigester psd = new PooledStringDigester();

        psd.setPoolSize(2);
        psd.setAlgorithm("SHA-256");
        psd.setIterations(1000);
        psd.setSaltSizeBytes(16);
        psd.setSaltGenerator(randomSaltGenerator());

        return psd;
    }

    @Bean
    public RandomSaltGenerator randomSaltGenerator() {
        RandomSaltGenerator randomSaltGenerator = new RandomSaltGenerator();
        return randomSaltGenerator;
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                .antMatchers("/static/**")
                .antMatchers("/i18n/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf()
        .and()
            .formLogin()
            .loginPage("/login")
            .loginProcessingUrl("/checkLogin")
            .defaultSuccessUrl("/home")
            .failureUrl("/login?login_error=1")
            .usernameParameter("username")
            .passwordParameter("password")
            .permitAll()
        .and()
            .logout()
            .logoutUrl("/logout")
            .logoutSuccessUrl("/login?isLoggedOut=1")
            .deleteCookies("JSESSIONID")
            .invalidateHttpSession(true)
            .permitAll()
        .and()
            .authorizeRequests()
            .antMatchers("/login**").permitAll()
            .antMatchers("/error**").permitAll()
            .antMatchers("/checkLogin**").permitAll()
            .anyRequest()
            .authenticated()
            .accessDecisionManager(accessDecisionManager)
        .and()
            .exceptionHandling()
            .accessDeniedPage("/accessDenied")
        .and()
            .headers()
            .frameOptions()
            .disable()
        .and()
            .sessionManagement()
            .invalidSessionUrl("/login")
            .maximumSessions(1);
    }

}

和我的自定义选民impl

@Component
public class AccessDecisionVoterImpl implements AccessDecisionVoter {

    @Autowired
    private ModuleService moduleService;

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    @Override
    public boolean supports(Class clazz) {
        return true;
    }

    @Override
    public int vote(Authentication authentication, Object object, Collection collection) {
// i have given this so that if user is not logged in then should not check permission at all 
        if(authentication instanceof AnonymousAuthenticationToken)
            return ACCESS_DENIED;

             HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
    String requestedOperation = request.getParameter("operation");

    if (requestedOperation != null && !requestedOperation.isEmpty()){
        String [] requestURISplit = request.getRequestURI().split("/");
        String requestedModuleName = requestURISplit[2];

        if(SecurityUtils.hasPermission(requestedModuleName, requestedOperation)){
           return ACCESS_GRANTED;
        }
    } else {
        return ACCESS_GRANTED;
    }

    return ACCESS_DENIED; 

此外,当我从选民中删除以下行时,如果用户未登录并尝试访问受保护的页面,则会继续。 它应该已重定向到登录页面。

if(authentication instanceof AnonymousAuthenticationToken)
                return ACCESS_DENIED;

这是我第一次尝试使用弹簧靴。 因此,我不确定所有的配置问题。

antMatchers的顺序有什么问题吗?

请帮忙。

您的AccessDecisionVoter需要

  • 弃权投票( AccessDecisionVoter.ACCESS_ABSTAIN ):如果选民无法做出决定(例如,用户未经授权,无法从请求上下文等获取模块)
  • 授予访问权限( AccessDecisionVoter.ACCESS_GRANTED ):如果可以识别模块并且用户被授权
  • 拒绝访问( AccessDecisionVoter.ACCESS_DENIED ):如果可以识别模块并且用户未被授权

使用AccessDecisionManager配置,您基本上可以取消基于URL的访问限制,例如:

http.authorizeRequests()
    .antMatchers("/css/**", "/img/**", "/js/**", "/font/**").permitAll()
    .antMatchers("/login**").permitAll()
    .antMatchers("/error**").permitAll()
    .antMatchers("/checkLogin**").permitAll()
    .anyRequest()
        .authenticated()

默认情况下,spring使用WebExpressionVoter来实现此目的。 但是,如果至少有一个AccessDecisionVoter授予对资源的访问权限,则AffirmativeBased AccessDecisionManager将授予访问权限(这可能不是您想要的)。 根据您的要求,包含WebExpressionVoterConsensusBased AccessDecisionManager将是最佳匹配。

@Bean
public AccessDecisionManager accessDecisionManager() {
    List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList<>();
    decisionVoters.add(new WebExpressionVoter());
    decisionVoters.add(new ModuleAccessDecisionVoter());
    ConsensusBased consensusBased = new ConsensusBased(decisionVoters);

    // deny access if voters equally voted to allow and deny access
    consensusBased.setAllowIfEqualGrantedDeniedDecisions(false);
    return consensusBased;
}

您的AccessDecisionVoter实现:

static class ModuleAccessDecisionVoter implements AccessDecisionVoter<FilterInvocation> {

    public int vote(Authentication authentication, FilterInvocation object, Collection<ConfigAttribute> attributes) {
        if (authentication == null || authentication instanceof AnonymousAuthenticationToken) {
            return ACCESS_ABSTAIN;
        }

        // determine module and grant or deny access
        // if module cannot be determined abstain from voting
        String module = determineModule(object);
        if (module != null) {
            return isAccessGranted(module, authentication) ? ACCESS_GRANTED : ACCESS_DENIED
        }

        return ACCESS_ABSTAIN;
    }
}

匿名访问应导致以下结果:

  • /login :WebExpressionVoter: +1 ,ModuleVoter: 0 - > 1 = ACCESS_GRANTED
  • /foo-module :WebExpressionVoter: -1 ,ModuleVoter: -1 - > -2 = ACCESS_DENIED

给定允许查看Foo模块的用户应该产生以下结果:

  • /foo-module :WebExpressionVoter: +1 ,ModuleVoter: +1 - > 2 = ACCESS_GRANTED
  • /bar-module :WebExpressionVoter: +1 (因为用户已通过身份验证),ModuleVoter: -1 - > 0 = ACCESS_DENIED (因为ConsensusBased.setAllowIfEqualGrantedDeniedDecisions(false)

如果我正确读取此内容,您将尝试通过返回ACCESS_DENIED进行匿名身份验证来解决用户匿名登录的问题。 那不好。 删除该自定义代码,而不是在安全配置中执行此操作:

anyRequest().hasRole("USER")

然后,确保在用户登录时,他们具有所需的角色。

另一种方法是禁用匿名登录,这样您就不需要角色(长期不推荐这样做)。

http.anonymous().disable()

问题来自你的选民。 如果配置了相关的“ConfigAttribute”,您的选民应该允许匿名访问。 以下是您应该添加的内容(可能取决于您的Spring Security版本):

for (ConfigAttribute attribute : collection) {
    if ("IS_AUTHENTICATED_ANONYMOUSLY".equals(attribute.getAttribute())) {
        return ACCESS_GRANTED;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM