当前位置: 首页 > 知识库问答 >
问题:

使用Spring-security@preauthorize注释和OAuth2保护REST API

宗政安歌
2023-03-14
  • Spring.version:4.0.5.release
  • Spring security Version:3.2.5.release
  • Spring security oauth版本:2.0.2.release
  • 球衣版本:1.18.1

我想使用Spring security的PreAuthorize注释来保护我的REST API,在这里我定义了被授权访问方法的角色:

@Transactional
@POST
@PreAuthorize("hasRole('ROLE_ADMIN')")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response create(User user) throws BusinessException {
    LOG.info("POST Request: Creation of a new user with username [{}]", user.getUsername());
    UserValidator.validateUser(user);
    User createdUser = userDao.create(user);
    return Response.ok(createdUser).build();
}

当我使用角色为“role_admin”的用户的有效承载令牌调用API方法时,我会得到以下异常:

09-Sep-2014 16:13:40.977 SEVERE [http-nio-8080-exec-6] com.sun.jersey.spi.container.ContainerResponse.mapMappableContainerException The RuntimeException     could not be mapped to a response, re-throwing to the HTTP container
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AbstractAccessDecisionManager.checkAllowIfAllAbstainDecisions(AbstractAccessDecisionManager.java:70)
at org.springframework.security.access.vote.UnanimousBased.decide(UnanimousBased.java:107)
at ...
{
    "error": "unauthorized",
    "error_description": "Full authentication is required to access this resource"
}
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
   xmlns:sec="http://www.springframework.org/schema/security"
   xsi:schemaLocation="http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-3.2.xsd
    http://www.springframework.org/schema/security/oauth2
    http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd">

<context:property-placeholder location="classpath:main.properties"/>

<sec:global-method-security pre-post-annotations="enabled" />

<oauth:expression-handler id="oauthExpressionHandler" />

<!-- Definition of the Authentication Service -->
<sec:http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager">
    <sec:intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY"/>
    <sec:anonymous enabled="false"/>
    <sec:http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
    <!--     include this only if you need to authenticate clients via request parameters -->
    <sec:custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER"/>
    <sec:access-denied-handler ref="oauthAccessDeniedHandler"/>
</sec:http>

<!-- Protected resources -->
<sec:http auto-config="true"
    entry-point-ref="oauthAuthenticationEntryPoint"/>

<bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
    <property name="realmName" value="dstest" />
</bean>

<bean id="clientAuthenticationEntryPoint"
      class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
    <property name="realmName" value="dstest/client"/>
    <property name="typeName" value="Basic"/>
</bean>

<bean id="oauthAccessDeniedHandler"
      class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>

<bean id="clientCredentialsTokenEndpointFilter"
      class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
    <property name="authenticationManager" ref="clientAuthenticationManager"/>
</bean>

<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
    <constructor-arg>
        <list>
            <bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter"/>
            <bean class="org.springframework.security.access.vote.RoleVoter"/>
            <bean class="org.springframework.security.access.vote.AuthenticatedVoter"/>
        </list>
    </constructor-arg>
</bean>

<!-- Authentication in config file -->
<sec:authentication-manager id="clientAuthenticationManager">
    <sec:authentication-provider user-service-ref="clientDetailsUserService"/>
</sec:authentication-manager>

<sec:authentication-manager alias="authenticationManager">
    <sec:authentication-provider>
        <sec:jdbc-user-service data-source-ref="securityDataSource"/>
    </sec:authentication-provider>
</sec:authentication-manager>

<bean id="clientDetailsUserService"
      class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
    <constructor-arg ref="clientDetails"/>
</bean>

<!-- Token Store  -->
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore">
    <constructor-arg ref="securityDataSource" />
</bean>

<bean id="oAuth2RequestFactory" class="org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory">
    <constructor-arg ref="clientDetails"/>
</bean>

<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
    <property name="tokenStore" ref="tokenStore"/>
    <property name="supportRefreshToken" value="true"/>
    <property name="clientDetailsService" ref="clientDetails"/>
    <!-- VIV -->
    <property name="accessTokenValiditySeconds" value="10"/>
</bean>

<bean id="userApprovalHandler"
      class="org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler">
    <property name="tokenStore" ref="tokenStore"/>
    <property name="requestFactory" ref="oAuth2RequestFactory"/>
</bean>

<!-- Token management -->
<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices"
                            user-approval-handler-ref="userApprovalHandler" token-endpoint-url="/oauth/token">
    <oauth:authorization-code/>
    <oauth:implicit/>
    <oauth:refresh-token/>
    <oauth:client-credentials/>
    <oauth:password/>
</oauth:authorization-server>

<oauth:resource-server id="resourceServerFilter"
                       resource-id="dstest"
                       token-services-ref="tokenServices"/>

<!-- Client Definition -->
<oauth:client-details-service id="clientDetails">
    <oauth:client client-id="healthdata-client"
                  authorized-grant-types="password,authorization_code,refresh_token,implicit,redirect"
                  authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT"
                  redirect-uri="/web"
                  scope="read,write,trust"
                  access-token-validity="300"
                  refresh-token-validity="6000"/>
</oauth:client-details-service>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">

    <display-name>Spring MVC Application BASIC AUTH</display-name>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:applicationContext.xml
            /WEB-INF/rest-dispatcher-servlet.xml
            /WEB-INF/security.xml
        </param-value>
    </context-param>

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

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

    <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>

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

    <servlet-mapping>
        <servlet-name>rest-dispatcher</servlet-name>
        <url-pattern>/oauth/token</url-pattern>
    </servlet-mapping>
    <servlet>

        <servlet-name>Spring servlets</servlet-name>
        <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>be.spring.security.api</param-value>
        </init-param>
        <init-param>
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>be.spring;org.codehaus.jackson.jaxrs</param-value>
        </init-param>
        <!-- optional: JSON support apart from jaxb -->
        <init-param>
            <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
            <param-value>true</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Spring servlets</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

共有1个答案

乐正锦
2023-03-14

我找到了解决我问题的办法。Web安全服务是使用该元素配置的,我必须将受保护的资源定义从:

<sec:http auto-config="true"
    entry-point-ref="oauthAuthenticationEntryPoint"/>

致:

<sec:http auto-config="true">
    <sec:custom-filter ref="resourceServerFilter"
                       before="PRE_AUTH_FILTER"/>
    <sec:access-denied-handler
            ref="oauthAccessDeniedHandler"/>
</sec:http>

必须引用resourceServerFilter,才能由安全机制拾取,并且必须将before属性设置为“pre_auth_filter”。

 类似资料:
  • 我正在使用osgi和基于spring注释的配置。(使用virgo部署应用程序) @preauthorize方法impl上的注释不起作用。 尽管用户没有该角色,但它仍允许用户访问它。 如果我在接口上放置相同的注释,它会为所有用户抛出AccessDenied异常。例外情况: 这是我的配置: 我使用的是spring-security 3.0.4.Release

  • 我正在开发一个spring rest项目,并使用OAuth2.0来保护这些API免受未经授权的访问。 前端:Angular.js后端:Spring Rest+Spring Security+Oauth2 2)我从后端获得了一个令牌,并使用该令牌来访问API。 现在我的问题是,一旦我用/oauth/token点击后端?grant_type=password&client_id=angularapp&

  • 我正在开发配置了SSO/OAuth2安全性的Spring Boot应用程序。身份验证对我的rest控制器很有效,现在我需要用restendpoint保护我的Apache Camel路由。 据我所知,有几种方法可以做到这一点: 通过将身份验证处理器添加到我的路线 通过向我的路线添加策略(SpringSecurityAuthorizationPolicy) jettyendpoint的“按处理程序”选

  • 我们正在构建一个REST资源服务器(一个Java示例应用程序),我们计划使用MITREID Connect项目提供的RFC7662定义的标识传播机制来保护它。我们测试了两种配置方法,XML设置,以及添加到resource server类中的基于注释的设置(参见下面附上的示例代码)。 我们的测试显示了Spring Security例程的成功初始化,但是我们没有成功地触发通过授权头的承载令牌通过。请求

  • 问题内容: 我成功配置了spring-security- oauth2,以便外部应用程序可以通过我的应用程序进行身份验证。但是,基于外部应用程序以及基于用户允许的内容,客户端只能访问我的API的子集。可用子集由OAuth范围确定。 在经典的Spring应用程序中,我可以使用@PreAuthorize来基于角色强制执行边界: 在使用OAuth并结合作用域而不是角色时,我该怎么做? 问题答案: Spr

  • 我创建了一个包含一些基本crud方法的CrudController。这很好用。当我想保护这个控制器时,我可以重写超类中的方法,这很好。然而,我不想仅仅为了安全而重写每个方法。为此,我想在类上使用@Secured或@PreAuthorize。 我使用的是Spring Boot 2.2.2(最新版本)。 示例Crud基类 实现类 预期行为 当一个类被注释为@PreAuthorize或@安全时,我希望所