ignored Security annotations in spring mvc

2019-05-04 20:53发布

问题:

I'm trying to configure spring secure annotations, I already managed to set spring security configuration in xml(configured by intercept-url elements), but now I'm want to use security annotations in my beans. But secured annotation is totaly ignored when try to access secured controller method without logging. Here is my controller bean:

package com.bill.controllers;

import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MainController {

    @Secured({"ROLE_USER"})
    @RequestMapping("/index.html")
    public String main(ModelMap model) {
        model.addAttribute("test", "test");

        return "main";
    }
}

and login controller:

package com.bill.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class LoginController {

    @RequestMapping("/login")
    public String login(ModelMap model) {
        return "login";
    }
}

and configurations: web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <display-name>tests</display-name>

    <servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

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

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring-servlet.xml,
            /WEB-INF/spring-security.xml
        </param-value>
    </context-param>

    <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>
    </filter-mapping>

</web-app>

spring-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>

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

    <context:component-scan base-package="com.bill" />

    <context:annotation-config />

    <!-- validation configuration -->
    <bean id="validator"
        class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />

    <mvc:annotation-driven validator="validator" />

    <!-- view configuration for thymeleaf -->
    <bean id="templateResolver"
        class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
        <property name="prefix" value="/WEB-INF/templates/" />
        <property name="suffix" value=".html" />
        <property name="templateMode" value="HTML5" />
        <property name="characterEncoding" value="UTF-8" />
        <property name="cacheable" value="false" />
    </bean>

    <bean id="templateEngine" class="org.thymeleaf.spring3.SpringTemplateEngine">
        <property name="templateResolver" ref="templateResolver" />
    </bean>

    <bean class="org.thymeleaf.spring3.view.ThymeleafViewResolver">
        <property name="templateEngine" ref="templateEngine" />
        <property name="characterEncoding" value="UTF-8" />
    </bean>

    <!-- messages configuration -->
    <bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="classpath:messages/messages" />
        <property name="defaultEncoding" value="UTF-8" />
    </bean>

    <!-- internalization configuration -->
    <bean id="localeChangeInterceptor"
        class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
        <property name="paramName" value="language" />
    </bean>

    <bean
        class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
        <property name="interceptors">
            <list>
                <ref bean="localeChangeInterceptor" />
            </list>
        </property>
    </bean>

    <!-- datasource configuration for hibernate 4 -->
    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/bill" />
        <property name="username" value="root" />
        <property name="password" value="****" />
    </bean>

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

    <tx:annotation-driven />

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

</beans>

and spring-security.xml

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <http auto-config="true">
        <form-login login-page="/login" default-target-url="/index.html" authentication-failure-url="/login" />
        <logout logout-success-url="/index.html" />
        <anonymous granted-authority="ROLE_GUEST" username="Guest"/>
    </http>

    <authentication-manager>
        <authentication-provider>
            <password-encoder hash="sha-256"/>
            <jdbc-user-service data-source-ref="dataSource"
               users-by-username-query="
                  select LOGIN, PASSWORD, 'true' 
                  from USERS where LOGIN=?" 
               authorities-by-username-query="
                  select LOGIN, ROLE from USERS
                  where LOGIN=?" 
            />
        </authentication-provider>
    </authentication-manager>

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

</beans:beans>

If it will be needed I can also paste here my pom.xml, but I think that this is poblem with my configuration(because this example without security works fine, and with security configured in xml it also works). I will be realy glad if someone can tell me where is my mistake.

回答1:

You have global method security enabled in the spring-security.xml which is processed by the root web application context.

The controllers reside inside the dispatcher servlet context and are unaffected by the bean postprocessors of the root web app context.

So you have to declare <security:global-method-security secured-annotations="enabled" /> inside the dispatcher servlet context or use the web level spring security tags instead(which seems to be natural for the web pages).

See Difference between applicationContext.xml and spring-servlet.xml in Spring Framework

Technically the bean post processors(and therefore AOP tools too) work on per container basis - therefore the things like @Secured or @Transactional will only work in the same application context where the respective annotations - <security:global-method-security ../> / <tx:annotation-driven/> have been applied.



回答2:

Are you sure your spring-security.xml is being loaded, and if it is, that it's being loaded in the right place. Have a look at this for some hints.