Spring MVC REST + Spring Security + 基本身份验证

Posted

技术标签:

【中文标题】Spring MVC REST + Spring Security + 基本身份验证【英文标题】:Spring MVC REST + Spring Security + Basic Authentication 【发布时间】:2016-04-30 23:05:02 【问题描述】:

环境:

春季 4.1

Spring 安全 4.0

问题:

我正在使用 Spring 4.1 开发一个简单的 REST 服务。并使用 Spring 安全性进行身份验证。 我正在使用 HTTP 基本身份验证。

问题是,即使所有配置都正确,基本身份验证也不起作用。 我正在使用邮递员向服务器发送请求。 REST 客户端可以在没有 Authorization 标头的情况下调用 REST 控制器方法。 该方法成功执行,没有任何身份验证错误。

由于我使用的是 Tomcat 6,我没有使用 servlet 3.0 features,所以 web.xml 确实存在。 方法级安全性已在 REST 控制器层上使用@Secured 注解实现。

任何人都可以帮我解决我哪里出错了吗?

代码:

web.xml

<web-app>
    <display-name>Archetype Created Web Application</display-name>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener> 

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/mvc-dispatcher-servlet-security.xml</param-value>
    </context-param>

    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
        </init-param>       
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>REQUEST</dispatcher>      
    </filter-mapping>

</web-app>

mvc-servlet-dispatcher-security.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="
        http://www.springframework.org/schema/security 
        http://www.springframework.org/schema/security/spring-security-4.0.xsd
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">

    <http use-expressions="true" create-session="stateless">
        <http-basic/>
       <csrf disabled="true"/> 
    </http>

    <global-method-security secured-annotations="enabled"/>

    <authentication-manager>
        <authentication-provider>
            <user-service>
                <user name="XYZ" password="12345" authorities="ROLE_USER" />
            </user-service>
        </authentication-provider>
    </authentication-manager>

</beans:beans>

mvc-dispatcher-servlet.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- Specifying base package of the Components like Controller, Service, DAO -->
    <context:component-scan base-package="org.ngo" />
    <!-- Getting Database properties -->
    <context:property-placeholder location="classpath:application.properties"/>

    <mvc:annotation-driven/>

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="$jdbc.driverClassName" />
        <property name="url" value="$jdbc.url" />
        <property name="username" value="$jdbc.username" />
        <property name="password" value="$jdbc.password" />
    </bean>

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource">
            <ref bean="dataSource" />
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.mysqlDialect</prop>
                <prop key="hibernate.show_sql">true</prop>              
            </props>
        </property>
        <property name="packagesToScan" value="org.ngo.abhishek.entity"></property>
    </bean>

    <!-- Transaction -->
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager" />
</beans>

REST 控制器:

@RestController
@RequestMapping("/abhishek")
public class AbhishekController 

    @Autowired
    private AbhisheskService abhishekService;

    @RequestMapping(method=RequestMethod.POST,consumes="application/json")
    @Secured("ROLE_USER")
    public ResponseEntity<Boolean> getUserById(@RequestBody List<AbhishekDTO> abhishekDtoList) 

        boolean flag = this.abhishekService.createAbhishek(abhishekDtoList);    
        return new ResponseEntity<Boolean>(flag, HttpStatus.OK);     
    


【问题讨论】:

【参考方案1】:

我尝试了您的设置,它对我有用。由于您没有提供所有代码,我最好的猜测是您的控制器的 Spring Security 组件扫描没有发生,或者您的浏览器正在缓存并发送基本身份验证凭据而您没有意识到。

【讨论】:

感谢您的回复。我会检查这两件事【参考方案2】:

从 Stiletto 获得线索后,我删除了 @Secured("ROLE_USER") 并使用基于表达式的安全检查。它有效(使用拦截网址)。所以问题在于@Secured 的放置位置。

由于 @Secured 在调度程序 servlet 上下文中(根据 Spring 哲学的子上下文)并且 spring 安全范围在 applicationContext(父上下文)中,因此 spring 安全性被忽略了。

&lt;security:global-method-security secured-annotations="enabled"/&gt; 放入mvc-dispatcher-servlet.xml 解决了这个问题。

关于 SO 的类似问题:Spring MVC, Method level security

【讨论】:

以上是关于Spring MVC REST + Spring Security + 基本身份验证的主要内容,如果未能解决你的问题,请参考以下文章

Spring MVC 转换 Spring Rest Api

混合 Spring MVC + Spring Data Rest 会导致奇怪的 MVC 响应

两个 servlet 中的 Spring、MVC 和 REST

如何在 spring-mvc 中为 REST 查询提供对象列表?

Spring Security + Angular JS + Spring MVC Rest

Spring MVC、Rest 和 Shiro。 @RequiresAuthentication 不起作用