使用Spring Boot构建独立的OAuth服务器(三)

Java框架

浏览数:252

2020-6-8

使用Spring Boot构建独立的OAuth服务器(二) 中配置了一个独立的OAuth服务器,这里要对Resource,即需要保护的API进行配置,使其在被访问的时候,可以与OAuth服务器通信,根据Access Token获取相关授权信息。

下面会分别讲一下使用Spring MVC和Spring Boot这两种框架时的配置方法。

Spring MVC

  1. 在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>

     

  2. 添加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>

     

  3. 添加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>

     

  4. 编写受保护的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

  1. 在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>

     

  2. 在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

     

  3. 编写主类Application,启用Resource服务器功能
    @SpringBootApplication
    @EnableResourceServer
    public class Application {
    
    	public static void main(String[] args) {
    		SpringApplication.run(Application.class, args);
    	}
    
    }

     

  4. 编写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')");
        }
    
    }

     

测试方法

  1. 启动OAuth服务器
  2. 使用Maven运行Goal:Spring MVC为clean compile tomcat7:run,Spring Boot为clean spring-boot:run
  3. 直接访问http://127.0.0.1:8081/user,会得到如下结果
    {
        "error": "unauthorized",
        "error_description": "Full authentication is required to access this resource"
    }

     

  4. 携带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则没有这个问题

作者:MrCamel