在 使用Spring Boot构建独立的OAuth服务器(二) 中配置了一个独立的OAuth服务器,这里要对Resource,即需要保护的API进行配置,使其在被访问的时候,可以与OAuth服务器通信,根据Access Token获取相关授权信息。
下面会分别讲一下使用Spring MVC和Spring Boot这两种框架时的配置方法。
Spring MVC
- 在pom.xml中配置依赖项和插件
<properties> <spring.version>3.2.13.RELEASE</spring.version> <spring.oauth.version>2.0.0.RELEASE</spring.oauth.version> <servlet.version>2.5</servlet.version> <jackson.version>1.9.13</jackson.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</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-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</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-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-core-asl</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> <version>${spring.oauth.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.0</version> <configuration> <path>/</path> <port>8081</port> </configuration> </plugin> </plugins> </build>
- 添加spring-mvc.xml,配置MVC功能
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="*" /> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messageConverters"> <list> <ref bean="mappingJacksonHttpMessageConverter" /> </list> </property> </bean> <bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>application/json; charset=UTF-8</value> </list> </property> </bean> </beans>
- 添加spring-security.xml,配置OAuth保护,使所有API只有角色为ROLE_USER的用户才能访问,注意create-session要设置为stateless,并且配置OAuth服务器连接信息(checkTokenEndpointUrl,clientId和clientSecret)
<?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:security="http://www.springframework.org/schema/security" xmlns:oauth2="http://www.springframework.org/schema/security/oauth2" 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"> <security:http pattern="/**" entry-point-ref="oauth2AuthenticationEntryPoint" use-expressions="true" create-session="stateless"> <security:intercept-url pattern="/*" access="hasAuthority('ROLE_USER')" /> <security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" /> </security:http> <oauth2:resource-server id="resourceServerFilter" token-services-ref="remoteTokenServices" /> <security:authentication-manager /> <bean id="remoteTokenServices" class="org.springframework.security.oauth2.provider.token.RemoteTokenServices"> <property name="checkTokenEndpointUrl" value="http://localhost:8080/oauth/check_token" /> <property name="clientId" value="client1" /> <property name="clientSecret" value="secret1" /> </bean> <bean id="oauth2AuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint" /> </beans>
- 编写受保护的Controller,返回结果为用户名
@Controller public class AuthorizedController { @RequestMapping(value = "/user", produces = "application/json; charset=UTF-8") @ResponseBody public Map<String, Object> user(Authentication auth) { Map<String, Object> result = new HashMap<String, Object>(); result.put("username", auth.getPrincipal()); return result; } }
Spring Boot
- 在pom.xml中配置依赖项和插件
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
- 在application.properties中配置OAuth服务器信息(security.oauth2.resource.token-info-uri,security.oauth2.client.client-id和security.oauth2.client.client-secret)
server.port=8081 security.oauth2.resource.token-info-uri=http://localhost:8080/oauth/check_token security.oauth2.client.client-id=client1 security.oauth2.client.client-secret=secret1
- 编写主类Application,启用Resource服务器功能
@SpringBootApplication @EnableResourceServer public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
- 编写Resource服务器配置类,使所有API只有角色为ROLE_USER的用户才能访问
@Configuration public class ResourceConfig extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.antMatcher("/**").authorizeRequests().anyRequest().access("hasAuthority('ROLE_USER')"); } }
测试方法
- 启动OAuth服务器
- 使用Maven运行Goal:Spring MVC为clean compile tomcat7:run,Spring Boot为clean spring-boot:run
- 直接访问http://127.0.0.1:8081/user,会得到如下结果
{ "error": "unauthorized", "error_description": "Full authentication is required to access this resource" }
- 携带Access Token去访问http://127.0.0.1:8081/user,会得到如下结果,其中user就是申请Access Token时使用的用户名
{ "username": "user" }
携带Access Token的方法有两种,第一种是使用名为access_token的参数传递过去,如http://127.0.0.1:8081/user?access_token=#ACCESS_TOKEN#,第二种是使用名为Authorization的Header传递过去,Header值的格式为Bearer #ACCESS_TOKEN#,基于安全考虑,推荐使用第二种
注意
使用Spring MVC时,create-session一定要设置为stateless,否则,在第一次访问成功后,短时间内再访问的时候如果不携带Access Token的话也能访问成功,原因是Spring Security会在第一次访问成功后创建一个session来存储授权信息,而使用Spring Boot则没有这个问题