差不多有两周的时间了,都在玩这个spring-security-oauth2,网上有不少资料,也看了不少,但始终自己调不通,最后通过一个网上可以调通的例子与我本机进行逐行debug对比,终于发现了问题。
这里记录一下这两周的心得。
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:///POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http:///POM/4.0.0 http:///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://</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 {
("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
return getExceptionTranslator().translate(e);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<OAuth2Exception> handleException(Exception e) throws Exception {
("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
return getExceptionTranslator().translate(e);
}
@ExceptionHandler(ClientRegistrationException.class)
public ResponseEntity<OAuth2Exception> handleClientRegistrationException(Exception e) throws Exception {
("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
return getExceptionTranslator().translate(new BadClientCredentialsException());
}
@ExceptionHandler(OAuth2Exception.class)
public ResponseEntity<OAuth2Exception> handleException(OAuth2Exception e) throws Exception {
("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请求保护的资源