zoukankan      html  css  js  c++  java
  • spring-security-oauth2使用

    差不多有两周的时间了,都在玩这个spring-security-oauth2,网上有不少资料,也看了不少,但始终自己调不通,最后通过一个网上可以调通的例子与我本机进行逐行debug对比,终于发现了问题。

    这里记录一下这两周的心得。

    参考资料(未完全列出):

    http://patrick002.iteye.com/blog/2207795

    http://wwwcomy.iteye.com/blog/2230265

    1、误区

    网上很多的资料,包括成功的案例,大都不是最新的oauth,然而最新的oauth却跟之前的有很多不同,所以借鉴网上的案例之前,要先确保环境跟它一样,否则可能会跑不通。

    问题是根据 Spring security oauth2最简单入门环境搭建--二、干货 一文发现的,因为这个例子我放到本机居然跑通了,但我自己做的demo写的一样居然跑不通。

    2、环境

    备注:这里要特别注意当前所使用的环境,即各种jar的版本

    我的问题主要就出在spring-security-oauth2-2.1.0.jar,而上面文章里用的是spring-security-oauth2-2.0.2.jar,这两个jar中的差距太大了,会直接影响oauth的整个配置

    附:我自己的pom.xml,基本上都是用的目前官网最新的jar

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.flysand</groupId>
      <artifactId>Test</artifactId>
      <packaging>war</packaging>
      <version>1.0-SNAPSHOT</version>
      <name>Test Maven Webapp</name>
      <url>http://maven.apache.org</url>
    
    
      <properties>
    
        <spring-version>4.3.7.RELEASE</spring-version>
        <spring-security-version>4.2.2.RELEASE</spring-security-version>
        <spring-security-oauth2-version>2.1.0.RELEASE</spring-security-oauth2-version>
        <mybatis-version>3.4.2</mybatis-version>
        <mybatis-spring-version>1.3.1</mybatis-spring-version>
        <druid-version>1.0.29</druid-version>
        <fastjson-version>1.2.30</fastjson-version>
        <logback-version>1.2.2</logback-version>
        <mysql-version>5.1.41</mysql-version>
        <servlet-api-version>4.0.0-b03</servlet-api-version>
        <jstl-version>1.2</jstl-version>
        <commons-codec-version>1.10</commons-codec-version>
        <jackson-version>2.8.7</jackson-version>
        <pageHelper-version>4.2.1</pageHelper-version>
    
      </properties>
    
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>${mysql-version}</version>
        </dependency>
        <dependency>
          <groupId>commons-codec</groupId>
          <artifactId>commons-codec</artifactId>
          <version>${commons-codec-version}</version>
        </dependency>
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>${jackson-version}</version>
        </dependency>
        <dependency>
          <groupId>com.github.pagehelper</groupId>
          <artifactId>pagehelper</artifactId>
          <version>${pageHelper-version}</version>
        </dependency>
    
        <!--spring  springMvc -->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>${spring-version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-web</artifactId>
          <version>${spring-version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>${spring-version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-beans</artifactId>
          <version>${spring-version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-aop</artifactId>
          <version>${spring-version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context-support</artifactId>
          <version>${spring-version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-tx</artifactId>
          <version>${spring-version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-orm</artifactId>
          <version>${spring-version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-test</artifactId>
          <version>${spring-version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-jdbc</artifactId>
          <version>${spring-version}</version>
        </dependency>
    
        <!-- spring security -->
        <dependency>
          <groupId>org.springframework.security</groupId>
          <artifactId>spring-security-core</artifactId>
          <version>${spring-security-version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework.security</groupId>
          <artifactId>spring-security-web</artifactId>
          <version>${spring-security-version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework.security</groupId>
          <artifactId>spring-security-config</artifactId>
          <version>${spring-security-version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework.security</groupId>
          <artifactId>spring-security-taglibs</artifactId>
          <version>${spring-security-version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.springframework.security.oauth</groupId>
          <artifactId>spring-security-oauth2</artifactId>
          <version>${spring-security-oauth2-version}</version>
        </dependency>
    
        <!--mybatis 数据库相关-->
        <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis</artifactId>
          <version>${mybatis-version}</version>
        </dependency>
        <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis-spring</artifactId>
          <version>${mybatis-spring-version}</version>
        </dependency>
        <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>druid</artifactId>
          <version>${druid-version}</version>
        </dependency>
    
        <!--tools-->
        <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>fastjson</artifactId>
          <version>${fastjson-version}</version>
        </dependency>
    
        <!--logback -->
        <dependency>
          <groupId>ch.qos.logback</groupId>
          <artifactId>logback-classic</artifactId>
          <version>${logback-version}</version>
        </dependency>
    
        <!--servlet jstl -->
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>${servlet-api-version}</version>
        </dependency>
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>jstl</artifactId>
          <version>${jstl-version}</version>
        </dependency>
      </dependencies>
    
      <build>
        <finalName>Test</finalName>
      </build>
    </project>

    上面两个jar包的主要区别(影响我正常跑通的地方)

    1> 新版本的/oauth/token验证不再支持GET请求

    TokenEndpoint.java对比,新版本增加了对GET请求的禁止访问
    /*
     * Copyright 2002-2011 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.security.oauth2.provider.endpoint;
    
    import java.security.Principal;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.HashSet;
    import java.util.Map;
    import java.util.Set;
    
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpMethod;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.security.authentication.InsufficientAuthenticationException;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.oauth2.common.OAuth2AccessToken;
    import org.springframework.security.oauth2.common.exceptions.BadClientCredentialsException;
    import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
    import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
    import org.springframework.security.oauth2.common.exceptions.InvalidRequestException;
    import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
    import org.springframework.security.oauth2.common.exceptions.UnsupportedGrantTypeException;
    import org.springframework.security.oauth2.common.util.OAuth2Utils;
    import org.springframework.security.oauth2.provider.ClientDetails;
    import org.springframework.security.oauth2.provider.ClientRegistrationException;
    import org.springframework.security.oauth2.provider.OAuth2Authentication;
    import org.springframework.security.oauth2.provider.OAuth2RequestValidator;
    import org.springframework.security.oauth2.provider.TokenRequest;
    import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestValidator;
    import org.springframework.util.StringUtils;
    import org.springframework.web.HttpRequestMethodNotSupportedException;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    
    /**
     * <p>
     * Endpoint for token requests as described in the OAuth2 spec. Clients post requests with a <code>grant_type</code>
     * parameter (e.g. "authorization_code") and other parameters as determined by the grant type. Supported grant types are
     * handled by the provided {@link #setTokenGranter(org.springframework.security.oauth2.provider.TokenGranter) token
     * granter}.
     * </p>
     * 
     * <p>
     * Clients must be authenticated using a Spring Security {@link Authentication} to access this endpoint, and the client
     * id is extracted from the authentication token. The best way to arrange this (as per the OAuth2 spec) is to use HTTP
     * basic authentication for this endpoint with standard Spring Security support.
     * </p>
     * 
     * @author Dave Syer
     * 
     */
    @FrameworkEndpoint
    public class TokenEndpoint extends AbstractEndpoint {
    
        private OAuth2RequestValidator oAuth2RequestValidator = new DefaultOAuth2RequestValidator();
    
      //默认初始化允许的requestMethod只能是POST
    private Set<HttpMethod> allowedRequestMethods = new HashSet<HttpMethod>(Arrays.asList(HttpMethod.POST)); @RequestMapping(value = "/oauth/token", method=RequestMethod.GET) public ResponseEntity<OAuth2AccessToken> getAccessToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
        //当请求为GET时,抛异常
    if (!allowedRequestMethods.contains(HttpMethod.GET)) { throw new HttpRequestMethodNotSupportedException("GET"); } return postAccessToken(principal, parameters); } @RequestMapping(value = "/oauth/token", method=RequestMethod.POST) public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException { if (!(principal instanceof Authentication)) { throw new InsufficientAuthenticationException( "There is no client authentication. Try adding an appropriate authentication filter."); } String clientId = getClientId(principal); ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId); TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient); if (clientId != null && !clientId.equals("")) { // Only validate the client details if a client authenticated during this // request. if (!clientId.equals(tokenRequest.getClientId())) { // double check to make sure that the client ID in the token request is the same as that in the // authenticated client throw new InvalidClientException("Given client ID does not match authenticated client"); } } if (authenticatedClient != null) { oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient); } if (!StringUtils.hasText(tokenRequest.getGrantType())) { throw new InvalidRequestException("Missing grant type"); } if (tokenRequest.getGrantType().equals("implicit")) { throw new InvalidGrantException("Implicit grant type not supported from token endpoint"); } if (isAuthCodeRequest(parameters)) { // The scope was requested or determined during the authorization step if (!tokenRequest.getScope().isEmpty()) { logger.debug("Clearing scope of incoming token request"); tokenRequest.setScope(Collections.<String> emptySet()); } } if (isRefreshTokenRequest(parameters)) { // A refresh token has its own default scopes, so we should ignore any added by the factory here. tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE))); } OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest); if (token == null) { throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType()); } return getResponse(token); } /** * @param principal the currently authentication principal * @return a client id if there is one in the principal */ protected String getClientId(Principal principal) { Authentication client = (Authentication) principal; if (!client.isAuthenticated()) { throw new InsufficientAuthenticationException("The client is not authenticated."); } String clientId = client.getName(); if (client instanceof OAuth2Authentication) { // Might be a client and user combined authentication clientId = ((OAuth2Authentication) client).getOAuth2Request().getClientId(); } return clientId; }
      //增加GET方法不支持的异常处理方法 @ExceptionHandler(HttpRequestMethodNotSupportedException.
    class) public ResponseEntity<OAuth2Exception> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) throws Exception { logger.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage()); return getExceptionTranslator().translate(e); } @ExceptionHandler(Exception.class) public ResponseEntity<OAuth2Exception> handleException(Exception e) throws Exception { logger.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage()); return getExceptionTranslator().translate(e); } @ExceptionHandler(ClientRegistrationException.class) public ResponseEntity<OAuth2Exception> handleClientRegistrationException(Exception e) throws Exception { logger.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage()); return getExceptionTranslator().translate(new BadClientCredentialsException()); } @ExceptionHandler(OAuth2Exception.class) public ResponseEntity<OAuth2Exception> handleException(OAuth2Exception e) throws Exception { logger.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage()); return getExceptionTranslator().translate(e); } private ResponseEntity<OAuth2AccessToken> getResponse(OAuth2AccessToken accessToken) { HttpHeaders headers = new HttpHeaders(); headers.set("Cache-Control", "no-store"); headers.set("Pragma", "no-cache"); return new ResponseEntity<OAuth2AccessToken>(accessToken, headers, HttpStatus.OK); } private boolean isRefreshTokenRequest(Map<String, String> parameters) { return "refresh_token".equals(parameters.get("grant_type")) && parameters.get("refresh_token") != null; } private boolean isAuthCodeRequest(Map<String, String> parameters) { return "authorization_code".equals(parameters.get("grant_type")) && parameters.get("code") != null; } public void setOAuth2RequestValidator(OAuth2RequestValidator oAuth2RequestValidator) { this.oAuth2RequestValidator = oAuth2RequestValidator; } public void setAllowedRequestMethods(Set<HttpMethod> allowedRequestMethods) { this.allowedRequestMethods = allowedRequestMethods; } }

    2> spring-security-oauth2.xsd

    spring-security-oauth配置文件所依赖的命名空间。

    <!-- oauth2 授权服务器 -->
        <oauth2:authorization-server client-details-service-ref="clientDetailsService"
                                     token-services-ref="tokenServices" user-approval-handler-ref="userApprovalHandler">
            <oauth2:authorization-code/>
            <oauth2:implicit/>
            <oauth2:refresh-token/>
            <oauth2:client-credentials/>
         <--password验证的时候,配置验证所用的(自定义)认证管理器,否则新版本会直接调用上面的oauth的认证管理器--> <oauth2:password authentication-manager-ref="authenticationManager" /> </oauth2:authorization-server>
      <!--自定义的用户验证的认证管理器,注意这里的id,上面的案例写成了alias别名,貌似有问题-->
      <
    security:authentication-manager id="authenticationManager">
        <!--这里可配置user-service,jdbc-user-service(默认提供了jdbc数据库相关联的用户验证查询)-->
    <!--<security:authentication-provider user-service-ref="userService"> &lt;!&ndash;用户角色权限信息配置在userService里&ndash;&gt; </security:authentication-provider>--> <!--<security:authentication-provider> <security:user-service> &lt;!&ndash;指定当前用户的信息及权限&ndash;&gt; <security:user name="user" authorities="ROLE_USER" password="user"/> <security:user name="admin" authorities="IS_AUTHENTICATED_FULLY" password="admin"/> <security:user name="test1" authorities="IS_AUTHENTICATED_FULLY" password="123456"/> </security:user-service> </security:authentication-provider>--> <security:authentication-provider user-service-ref="userService"> </security:authentication-provider> </security:authentication-manager> <bean id="userService" class="com.flysand.oauth.MyUserService"/>

    因为限制限制GET请求,而spring-security本身自带csrf过滤器会自动拦截所有的POST请求,因此需要单独加一个例外的requestMatcher用来except oauth的请求。

    自定义的requestMatcher

    CsrfSecurityMatcher.java
    package com.flysand.matcher;
    
    import org.springframework.security.web.util.matcher.RequestMatcher;
    
    import javax.servlet.http.HttpServletRequest;
    import java.util.List;
    import java.util.regex.Pattern;
    
    /**
     * Title:CsrfSecurityMatcher.java
     * Location:com.flysand.matcher
     * Author:flysand
     * Date:2017年04月13 16:07:40
     * Description:
     **/
    public class CsrfSecurityMatcher implements RequestMatcher {
    
        private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");
    
        private List<String> execludeUrls;
    
        public boolean matches(HttpServletRequest request) {
    
            if(execludeUrls !=null && execludeUrls.size()>0){
                String servletPath =request.getServletPath();
                for(String url : execludeUrls){
                    if(servletPath.contains(url)){
                        return false;
                    }
                }
            }
    
            return !allowedMethods.matcher(request.getMethod()).matches();
        }
    
    
        public List<String> getExecludeUrls() {
            return execludeUrls;
        }
    
        public void setExecludeUrls(List<String> execludeUrls) {
            this.execludeUrls = execludeUrls;
        }
    }

    spring-security.xml中的配置

        <security:http pattern="/oauth/token" create-session="stateless"
                       authentication-manager-ref="clientAuthenticationManager">
            <security:intercept-url pattern="/oauth/token" access="hasRole('ROLE_USER')"/>
            <!--spring security 4 默认添加csrfFilter过滤器,限制所有post请求-->
            <security:csrf request-matcher-ref="csrfSecurityRequestMatcher"/>
            <security:anonymous enabled="false"/>
            <security:http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
            <security:custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER"/>
            <security:access-denied-handler ref="accessDeniedHandler"/>
        </security:http>
    
        <!--自定义requestMatcher用于解除list列表里的post请求的限制-->
        <bean id="csrfSecurityRequestMatcher" class="com.flysand.matcher.CsrfSecurityMatcher">
            <property name="execludeUrls">
                <list>
                    <value>/oauth/</value>
                </list>
            </property>
        </bean>

    这样基本上就可以了。

    其他配置基本上跟参考的资料里面配置一样

    附完整的spring-security.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:oauth2="http://www.springframework.org/schema/security/oauth2"
           xmlns:security="http://www.springframework.org/schema/security"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/security
                http://www.springframework.org/schema/security/spring-security.xsd
                http://www.springframework.org/schema/security/oauth2
                http://www.springframework.org/schema/security/spring-security-oauth2.xsd">
    
    
        <!--spring security 配置 -->
    
        <!--token 存储方式  InMemoryTokenStore内存  JDBC  jwt 等方式-->
        <bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore"/>
        <!--token 业务处理 这里用默认的  可以自定义-->
        <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="clientDetailsService"/>
        </bean>
    
        <!--client  认证接入点 -->
        <bean id="clientAuthenticationEntryPoint"
              class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint"/>
        <!--访问拒绝的handler -->
        <bean id="accessDeniedHandler"
              class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>
    
        <!--A default user approval handler that doesn't remember any decisions.-->
        <bean id="userApprovalHandler"
              class="org.springframework.security.oauth2.provider.approval.DefaultUserApprovalHandler"/>
    
        <!---clientdetails =-->
        <!--<bean id="clientDetailsService" class="com.flysand.web.**"/>-->
        <oauth2:client-details-service id="clientDetailsService">
            <oauth2:client client-id="client" authorized-grant-types="password" authorities="IS_AUTHENTICATED_FULLY"
                           secret="secret" scope="read,write,trust"/>
            <oauth2:client client-id="test1" authorities="IS_AUTHENTICATED_FULLY" authorized-grant-types="password" secret="123456" scope="read"/>
            <oauth2:client client-id="test" authorities="ROLE_USER" authorized-grant-types="password" secret="123456" scope="read"/>
            <oauth2:client client-id="user" authorities="ROLE_USER" authorized-grant-types="password" secret="user" scope="read,write"/>
        </oauth2:client-details-service>
        <!--<bean id="clientDetailsService" class="com.flysand.oauth.MyClientDetailsService"/>-->
    
    
        <bean id="clientDetailsUserDetailsService"
              class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
            <constructor-arg ref="clientDetailsService"/>
        </bean>
    
        <!--client 认证 管理器 -->
        <security:authentication-manager id="clientAuthenticationManager">
            <security:authentication-provider user-service-ref="clientDetailsUserDetailsService"/>
        </security:authentication-manager>
    
        <!--client credential endpoint filter
        A filter and authentication endpoint for the OAuth2 Token Endpoint-->
        <bean id="clientCredentialsTokenEndpointFilter"
              class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
            <property name="authenticationManager" ref="clientAuthenticationManager"/>
        </bean>
    
    
        <!-- oauth2 授权服务器 -->
        <oauth2:authorization-server client-details-service-ref="clientDetailsService"
                                     token-services-ref="tokenServices" user-approval-handler-ref="userApprovalHandler">
            <oauth2:authorization-code/>
            <oauth2:implicit/>
            <oauth2:refresh-token/>
            <oauth2:client-credentials/>
            <oauth2:password authentication-manager-ref="authenticationManager" />
        </oauth2:authorization-server>
    
        <!--http
        stateless 无状态session,默认create,每次都创建session会给服务器压力很大,
        不保存session状态,每次访问需要重新认证,即带user token
        详解http://www.cnblogs.com/Mainz/archive/2013/08/01/3230077.html-->
        <security:http pattern="/oauth/token" create-session="stateless"
                       authentication-manager-ref="clientAuthenticationManager">
            <security:intercept-url pattern="/oauth/token" access="hasRole('ROLE_USER')"/>
            <!--spring security 4 默认添加csrfFilter过滤器,限制所有post请求-->
            <security:csrf request-matcher-ref="csrfSecurityRequestMatcher"/>
            <security:anonymous enabled="false"/>
            <security:http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
            <security:custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER"/>
            <security:access-denied-handler ref="accessDeniedHandler"/>
        </security:http>
    
        <!--自定义requestMatcher用于解除list列表里的post请求的限制-->
        <bean id="csrfSecurityRequestMatcher" class="com.flysand.matcher.CsrfSecurityMatcher">
            <property name="execludeUrls">
                <list>
                    <value>/oauth/</value>
                </list>
            </property>
        </bean>
        <!-- user setting -->
        <!--<bean id="userService" class="com.flysand.service.UserService"/>-->
    
        <security:authentication-manager id="authenticationManager">
            <!--<security:authentication-provider user-service-ref="userService">
                &lt;!&ndash;用户角色权限信息配置在userService里&ndash;&gt;
            </security:authentication-provider>-->
            <!--<security:authentication-provider>
                <security:user-service>
                    &lt;!&ndash;指定当前用户的信息及权限&ndash;&gt;
                    <security:user name="user" authorities="ROLE_USER" password="user"/>
                    <security:user name="admin" authorities="IS_AUTHENTICATED_FULLY" password="admin"/>
                    <security:user name="test1" authorities="IS_AUTHENTICATED_FULLY" password="123456"/>
                </security:user-service>
            </security:authentication-provider>-->
            <security:authentication-provider user-service-ref="userService">
    
            </security:authentication-provider>
        </security:authentication-manager>
        <bean id="userService" class="com.flysand.oauth.MyUserService"/>
    
        <!--资源服务器-->
        <oauth2:resource-server id="myResourceService" resource-id="myresource" token-services-ref="tokenServices"/>
    
        <!--访问决策管理器-->
        <!--决策投票器 AffirmativeBased 一票通过 ConsensusBased少数服从多数 UnanimousBased全票通过
         其中 ConsensusBased少数服从多数——当投票数相等时,
         默认的private boolean allowIfEqualGrantedDeniedDecisions = true属性起作用,即只要不为0默认验证通过-->
        <!--<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
            <constructor-arg>
                <list>
                    &lt;!&ndash;投票器(权限验证规则),RoleVoter验证角色,AuthenticatedVoter当角色不存在时验证,
                    包括IS_AUTHENTICATED_FULLY,IS_AUTHENTICATED_REMEMBERED,IS_AUTHENTICATED_ANONYMOUSLY
                    WebExpressionVoter表达式投票器,必须设置,不然自定义的&ndash;&gt;
                    <bean class="org.springframework.security.web.access.expression.WebExpressionVoter"/>
                    <bean class="org.springframework.security.access.vote.RoleVoter"/>
                    <bean class="org.springframework.security.access.vote.AuthenticatedVoter"/>
                </list>
            </constructor-arg>
        </bean>-->
        <!--自定义accessDecisionManager-->
        <bean id="accessDecisionManager" class="com.flysand.access.MyAccessDecisionManager">
            <constructor-arg>
                <list>
                    <bean class="org.springframework.security.web.access.expression.WebExpressionVoter"/>
                </list>
            </constructor-arg>
        </bean>
    
        <!--资源http配置-->
        <security:http pattern="/abcs/**" create-session="never" entry-point-ref="clientAuthenticationEntryPoint"
                       access-decision-manager-ref="accessDecisionManager">
            <security:anonymous enabled="false"/>
            <security:intercept-url pattern="/abcs/**" access="hasRole('ROLE_USER')"/>
            <security:custom-filter ref="myResourceService" before="PRE_AUTH_FILTER"/>
            <security:access-denied-handler ref="accessDeniedHandler"/>
        </security:http>
    </beans>

     在t1.jsp里面写一个ajax请求用来获取access_token

    <%--
      Created by IntelliJ IDEA.
      User: jianyi
      Date: 2017年3月31日 0031
      Time: 13:47:16
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <meta name="_csrf" content="${_csrf.token}">
        <title>Title</title>
        <script type="text/javascript" src="js/jquery-1.12.4.min.js"></script>
        <script type="text/javascript">
            $(function () {
    
                var token = $("meta[name='_csrf']").attr("content");
                var header = $("meta[name='_csrf_header']").attr("content");
                $('#ajax').click(function () {
                    var url = "user/getUsers";
                    url = 'oauth/token';
                    $.ajax({
                        type:'post',
                        url:url,
                        dataType:'json',
                        data:'client_id=test&client_secret=123456&grant_type=password&username=user&password=123',
                        //data:'pageIndex=1&pageSize=10',
                        success:function(data){
                            console.log(data)
                        },
                        error:function (data) {
                            console.log("系统异常");
                        }/*,
                         complete:function (data) {
                         console.log(data);
                         }*/
    
                    });
    
                });
            });
        </script>
    </head>
    <body>
    mytest
    
    <input id="ajax" type="button" value="测试ajax"/>
    </body>
    </html>

    结果:

    根据access_token请求保护的资源

    完整项目:

    https://github.com/symflysand/OauthTest

  • 相关阅读:
    markdown 常用语法
    markdown 转 pdf 方法
    git call failed: [git clone Could not resolve host: git.openstack.org
    从VirtualBox虚拟主机访问NAT客户机的方法
    MVC,MVP 和 MVVM 的图示
    url转义
    Python如何输出包含在对象中的中文字符?
    OpenGL
    AutoHotKey使用:空格键坏了怎么办?
    三联书社推荐好书100本
  • 原文地址:https://www.cnblogs.com/flysand/p/6728879.html
Copyright © 2011-2022 走看看