使⽤Springboot搭建OAuth2.0Server的⽅法⽰例
OAuth是⼀个关于授权(authorization)的开放⽹络标准,在全世界得到⼴泛应⽤,⽬前的版本是2.0版。
本⽂对OAuth 2.0的设计思路和运⾏流程,做⼀个简明通俗的解释,主要参考材料为RFC 6749。
OAuth 简介
OAuth 是由 Blaine Cook、Chris Messina、Larry Halff 及 David Recordon 共同发起的,⽬的在于为 API 访问授权提供⼀个安全、开放的标准。
基于 OAuth 认证授权具有以下特点:
安全。OAuth 与别的授权⽅式不同之处在于:OAuth 的授权不会使消费⽅(Consumer)触及到⽤户的帐号信息(如⽤户名与密码),也是是说,消费⽅⽆需使⽤⽤户的⽤户名与密码就可以申请获得该⽤户资源的授权。
开放。任何消费⽅都可以使⽤ OAuth 认证服务,任何服务提供⽅ (Service Provider) 都可以实现⾃⾝的 OAuth 认证服务。
简单。不管是消费⽅还是服务提供⽅,都很容易于理解与使⽤。
OAuth 的解决⽅案如下图所⽰。
图 1. OAuth Solution
如图 1 所⽰ OAuth 解决⽅案中⽤户、消费⽅及其服务提供⽅之间的三⾓关系:当⽤户需要 Consumer 为其提供某种服务时,该服务涉及到需要从服务提供⽅那⾥获取该⽤户的保护资源。OAuth 保证:只有在⽤户显式授权的情况下(步骤 4),消费⽅才可以获取该⽤户的资源,并⽤来服务于该⽤户。
从宏观层次来看,OAuth 按以下⽅式⼯作:
消费⽅与不同的服务提供⽅建⽴了关系。
消费⽅共享⼀个密码短语或者是公钥给服务提供⽅,服务提供⽅使⽤该公钥来确认消费⽅的⾝份。
消费⽅根据服务提供⽅将⽤户重定向到登录页⾯。
该⽤户登录后告诉服务提供⽅该消费⽅访问他的保护资源是没问题的。前提
阅读本⽂之前,你需要了解:
Spring Boot
Spring MVC
Spring Security
Google 浏览器插件Postman
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="/POM/4.0.0" xmlns:xsi="/2001/XMLSchema-instance"
xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.iigrowing.study.oauth2</groupId>
<artifactId>demo01</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>my.oauth01</name>
<description>Demo project for Spring Boot</description>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
&porting.outputEncoding>UTF-8</porting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<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>
</project>
本项⽬需要添加的依赖⾮常简单,⼀共只有两个,⼀个是Spring Web,另⼀个是Spring OAuth2。接下来是本⽂的核⼼,⼀共三个配置类。
SecurityConfig
package cn.iigrowing.study.oauth2.demo01;
import t.annotation.Bean;
import t.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.fig.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.fig.annotation.web.builders.HttpSecurity;
import org.fig.figuration.EnableWebSecurity;
import org.fig.figuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("123456").authorities("ROLE_USER");
}
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic()
.and().csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.
logout().permitAll();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
此处主要做了两件事情:
配置系统⽤户,这⾥使⽤内存存储,添加了⽤户名为user,⾓⾊为USER的⽤户
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("123456").authorities("ROLE_USER");
}
配置了默认表单登陆以及禁⽤了csrf功能,并开启了httpBasic认证
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic()
.and().csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.
anyRequest().authenticated()
.and()
.formLogin()
.and()
.logout().permitAll();
}
AuthorizationServerConfig
package cn.iigrowing.study.oauth2.demo01;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import t.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
spring mvc和boot区别import org.springframework.figurers.ClientDetailsServiceConfigurer;
import org.springframework.fig.figuration.AuthorizationServerConfigurerAdapter; import org.springframework.fig.figuration.EnableAuthorizationServer;
import org.springframework.fig.figurers.AuthorizationServerEndpointsConfigurer; @Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client").secret("123456").scopes("read")
.authorizedGrantTypes("authorization_code")
.redirectUris("postman/oauth2/callback");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
}
这个类是OAuth2认证的核⼼配置类,在这个类中,配置了OAuth Client的信息,这⾥有⼏个地⽅需要注意:@EnableAuthorizationServer这个注解告诉 Spring 这个应⽤是 OAuth2 的授权服务器
必须配置authorizedGrantTypes
,它代表了OAuth Client允许认证的类型,其值主要有:
authorization_code
password
client_credentials
implicit refresh_token
这个配置项接受的类型是个数组,允许配置多个;关于这⼏种类型的区别,请查看这⾥不再赘述
package cn.iigrowing.study.oauth2.demo01;
import t.annotation.Configuration;
import org.fig.annotation.web.builders.HttpSecurity;
import org.fig.http.SessionCreationPolicy;
import org.springframework.fig.figuration.EnableResourceServer;
import org.springframework.fig.figuration.ResourceServerConfigurerAdapter;
import org.springframework.fig.figurers.ResourceServerSecurityConfigurer;
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.requestMatchers()
.antMatchers(“/users/**”)
.
and().authorizeRequests()
.antMatchers(“/users/**”)
.authenticated();
}
}
这个类表明了此应⽤是OAuth2 的资源服务器,此处主要指定了受资源服务器保护的资源链接,我们将提供以下的资源:
@RestController
@RequestMapping("users")
public class UserController {
@GetMapping("me")
public Principal me(Principal principal) {
return principal;
}
}
注:
资源服务器可以和授权服务器是同⼀个,也可以分开部署
最后,我们还需添加l , 配置资源服务器的filter的顺序
server:
port: 8043
context-path: /uaa
logging:
level:
org.springframework.security: DEBUG
spring:
application:
name: oauth-server
security:
oauth2:
resource:
serviceId: ${PREFIX:}resource
# refer to: github/spring-projects/spring-boot/wiki/Spring-Boot-1.5-Release-Notes#oauth-2-resource-filter
filter-order: 3
此处的filter-order⾮常重要,因为⾃Spring Boot 1.5.* 之后,resource server 的 filter 的顺序默认在basic authentication filter chain 之后,所以如果不配置此项,将会导致使⽤access_token访问 resource server 的时候返回401状态码。
因为现在还没通过认证,所以服务器将返回401的状态码,并返回以上的错误信息。
现在我们使⽤Postman来获取access_token,⾸先选择Authorization Tab, 然后选择Type为OAuth2.0,最后点击Get New Access Token按钮:
此时将弹出以下界⾯:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。