【问题标题】:Spring security configuration error for admin request管理员请求的 Spring 安全配置错误
【发布时间】:2015-09-07 14:47:50
【问题描述】:

我正在尝试将我的 Spring 应用程序配置为拥有一个非常基本的带有 Spring 安全性的安全系统。 我希望在没有安全过滤器的情况下提供资源,过滤标准页面以检查用户是否具有“用户”角色,并提供 /admin/ 页面以检查角色是否为“管理员”。

我拥有的是:

springSecurityFilterChain org.springframework.web.filter.DelegatingFilterProxy

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

在web.xml中,而spring-security.xml是:

<security:http security="none" pattern="/resources/**"/>
<security:http auto-config="true" use-expressions="true" >
    <security:intercept-url pattern="/admin/**" access="hasRole('Admin')" />
    <security:logout logout-success-url="/welcome" logout-url="/logout" />
    <security:form-login login-page="/FormLogin"
        default-target-url="/welcome"
        username-parameter="username"
        password-parameter="hashPwd" 
        authentication-failure-url="/login?error"
        />
</security:http>

<security:authentication-manager>
   <security:authentication-provider user-service-ref="controlloUtente">
     <security:password-encoder hash="bcrypt" />  
  </security:authentication-provider>
</security:authentication-manager>


<beans:bean id="controlloUtente"
    class="org.fabrizio.fantacalcio.utility.SpringSecurityServiceImpl">
</beans:bean>

然后我配置了这个类:

package org.fabrizio.fantacalcio.utility;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.fabrizio.fantacalcio.model.beans.Utente;
import org.fabrizio.fantacalcio.model.dao.UtenteDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class SpringSecurityServiceImpl implements UserDetailsService{

    @Autowired
    private UtenteDaoImpl utenteDao;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Utente utente = utenteDao.getUtenteByUsername(username);
        if(utente == null){
            throw new UsernameNotFoundException("L'utente inserito non è stato trovato");
        }
        return convertUtente(utente);
    }

    private UserDetails convertUtente(Utente utente) {
        UserDetails ud = new User(utente.getUsername(), utente.getHashPwd(), true, true, true, true, getRoles(utente));
        return ud;
    }

    private Collection<? extends GrantedAuthority> getRoles(Utente utente) {
        GrantedAuthority auth = new SimpleGrantedAuthority(utente.getRuolo().getNome());
        List<GrantedAuthority> listaAuth = new ArrayList<GrantedAuthority>();
        listaAuth.add(auth);
        return listaAuth;
    }

}

还有以下一个:

package org.fabrizio.fantacalcio.utility;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.PriorityOrdered;
import org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.stereotype.Component;

@Component
public class DefaultRolesPrefixPostProcessor implements BeanPostProcessor, PriorityOrdered {

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        if(bean instanceof Jsr250MethodSecurityMetadataSource) {
            ((Jsr250MethodSecurityMetadataSource) bean).setDefaultRolePrefix("");
        }
        if(bean instanceof DefaultMethodSecurityExpressionHandler) {
            ((DefaultMethodSecurityExpressionHandler) bean).setDefaultRolePrefix("");
        }
//        if(bean instanceof DefaultWebSecurityExpressionHandler) {
//            ((DefaultWebSecurityExpressionHandler) bean).setDefaultRolePrefix("");
//        }
        return bean;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        return bean;
    }

    @Override
    public int getOrder() {
        return PriorityOrdered.HIGHEST_PRECEDENCE;
    }
}

但是没有任何效果。 我的 formLogin 不使用弹簧表单,而是使用经典表单。

当我登录并尝试获取像 /admin/testpage 这样的 pge 时,即使我具有管理员角色,我也会被重定向到 FormLogin 页面,这是调试输出:

22/06/2015 10:03:04 - DEBUG - (AntPathRequestMatcher.java:141) - Request '/admin/formregistrazione' matched by universal pattern '/**'
22/06/2015 10:03:04 - DEBUG - (HttpSessionRequestCache.java:43) - DefaultSavedRequest added to Session: DefaultSavedRequest[http://localhost:8080/Fantacalcio/admin/FormRegistrazione]
22/06/2015 10:03:04 - DEBUG - (ExceptionTranslationFilter.java:202) - Calling Authentication entry point.
22/06/2015 10:03:04 - DEBUG - (DefaultRedirectStrategy.java:39) - Redirecting to 'http://localhost:8080/Fantacalcio/FormLogin'
22/06/2015 10:03:04 - DEBUG - (HttpSessionSecurityContextRepository.java:337) - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.

有时,登录后,我会收到以下消息:

HTTP Status 403 - Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.

我做错了什么?我总是必须使用令牌?为什么流程永远不会进入 SpringSecurityServiceImpl 类?

谢谢

编辑:我禁用了csrf,现在情况越来越清楚了。问题在于我的SpringSecurityServiceImpl Autowired utenteDao 实例为空。我像这样编辑了 spring-security.xml 文件,希望 Spring 理解 @Service 注释类但它不起作用:

<security:authentication-manager>
       <security:authentication-provider user-service-ref="SpringSecurityServiceImpl">
         <security:password-encoder hash="bcrypt" />  
      </security:authentication-provider>
    </security:authentication-manager>

我的 UtenteDao 课程

package org.fabrizio.fantacalcio.model.dao;

import java.util.List;

import org.fabrizio.fantacalcio.model.beans.Utente;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;

@Repository
public class UtenteDaoImpl extends BaseDaoImpl<Utente> implements UtenteDao{

     public UtenteDaoImpl() {
    System.out.println("test");
    }

    @SuppressWarnings("unchecked")
    public List<Utente> trovaUtentiAttivi(){
        return getSession().createCriteria(Utente.class).add(Restrictions.eq("attivo", true)).list();
    }


    @SuppressWarnings("unchecked")
    public Utente getUtenteFromCredenziali(Utente utente){
        List<Utente> utenteTrovato = getSession().createCriteria(Utente.class)
                .add(Restrictions.eq("username", utente.getUsername()))
                .add(Restrictions.eq("hashPwd", utente.getHashPwd()))
                .list();
        Utente utenteLoggato = utenteTrovato.size() == 0 ? null : utenteTrovato.get(0);
        return utenteLoggato;
    }

    public Boolean usernameExists(String username){
        return getSession().createCriteria(Utente.class)
                .add(Restrictions.eq("username", username))
                .list().size() > 0;
    }

    @SuppressWarnings("unchecked")
    public Utente getUtenteByUsername(String username){
        List<Utente> utenteTrovato = getSession().createCriteria(Utente.class)
                .add(Restrictions.eq("username", username))
                .list();
        Utente utenteLoggato = utenteTrovato.size() == 0 ? null : utenteTrovato.get(0);
        return utenteLoggato;
    }
}

【问题讨论】:

  • 为什么我在你的 securityApplicationContext.xml 中看不到任何 CSRF 配置?
  • 我问,我应该强制使用 csrf 令牌吗?
  • 其实没有,我看不到你在哪里配置 CSRF,所以你不应该得到那个错误。但是因为你有这个错误,你已经启用了 CSRF,尽管默认情况下它是启用的。
  • 或者在你的atConfiguration文件中,你可以把.csrf().disable();用于配置方法。
  • 在 Spring Security 4 中默认启用 csrf 保护,在早期版本中它是可选的 (jira.spring.io/browse/SEC-2347)。所以是的,你需要在所有表单中使用它,或者禁用 CSRF 保护。

标签: java spring spring-mvc spring-security


【解决方案1】:

Spring 安全登录和注销表单期望在发布请求中发送 CSRF 令牌。您可以使用隐藏变量添加令牌:

 <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

在 Spring Security 登录表单中添加以上行。并且注销也需要是post请求方法。每个对服务器的发布请求都会检查这些令牌,您可以将其设置到请求标头中。如果您不想这样做并禁用 csrf 令牌安全性。 您可以在安全配置的 http 部分中使用 csrf 标签禁用它。 csrf 具有禁用它的属性。

<http>
    <csrf />
</http>

阅读this article了解更多信息。

编辑:

您在安全认证标签中提到了user-service-ref="SpringSecurityServiceImpl",但Service 类没有标识符。给你的服务类一个标识符,首选驼峰字符。

@Service("springSecurityServiceImpl") // talking about this identifier
@Transactional
public class SpringSecurityServiceImpl implements UserDetailsService {}

身份验证提供者 bean 应该是:

<security:authentication-manager>
   <security:authentication-provider user-service-ref="springSecurityServiceImpl">
     <security:password-encoder hash="bcrypt" />  
  </security:authentication-provider>
</security:authentication-manager>

并且还要检查你的 DAO 类是否被标记为 @Repository 组件,以便 autowire 能够正常工作。

【讨论】:

  • 将其添加到xml配置文件并不会禁用csrf保护,我无法通过xml找到方法。
  • 你到底添加了什么?可以贴在这里吗。它应该类似于
  • 我禁用了它,但我遇到了一些新问题,我编辑了问题。
  • 我试过了,但没有成功。如果我没有在 xml 中定义 bean,我总是会收到找不到 bean 的错误,如果我在 xml 中声明它,bean 会被创建两次,我得到一个空 dao 对象。
  • 你的 标签是否涵盖了声明了 service 和 dao 类的包?
【解决方案2】:

我解决了这个问题。 四处搜索我发现security和servlet有不同的上下文,所以基本上我必须在security-config.xml文件上添加<context:component-scan base-package="org.fabrizio.fantacalcio.utility, org.fabrizio.fantacalcio.model.dao" /> ,只声明要扫描的包以使安全工作,因为它不共享在调度程序配置文件中声明的 bean。

【讨论】:

    猜你喜欢
    • 2021-11-23
    • 1970-01-01
    • 2020-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多