差不多有两周的时间了,都在玩这个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"> <!–用户角色权限信息配置在userService里–> </security:authentication-provider>--> <!--<security:authentication-provider> <security:user-service> <!–指定当前用户的信息及权限–> <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"> <!–用户角色权限信息配置在userService里–> </security:authentication-provider>--> <!--<security:authentication-provider> <security:user-service> <!–指定当前用户的信息及权限–> <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> <!–投票器(权限验证规则),RoleVoter验证角色,AuthenticatedVoter当角色不存在时验证, 包括IS_AUTHENTICATED_FULLY,IS_AUTHENTICATED_REMEMBERED,IS_AUTHENTICATED_ANONYMOUSLY WebExpressionVoter表达式投票器,必须设置,不然自定义的–> <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请求保护的资源
完整项目: