OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版。
本文对OAuth 2.0的设计思路和运行流程,做一个简明通俗的解释,主要参考材料为RFC 6749。
OAuth 简介
OAuth 是由 Blaine Cook、Chris Messina、Larry Halff 及 David Recordon 共同发起的,目的在于为 API 访问授权提供一个安全、开放的标准。
基于 OAuth 认证授权具有以下特点:
OAuth 的解决方案如下图所示。
图 1. OAuth Solution
如 图 1 所示 OAuth 解决方案中用户、消费方及其服务提供方之间的三角关系:当用户需要 Consumer 为其提供某种服务时,该服务涉及到需要从服务提供方那里获取该用户的保护资源。OAuth 保证:只有在用户显式授权的情况下(步骤 4),消费方才可以获取该用户的资源,并用来服务于该用户。
从宏观层次来看,OAuth 按以下方式工作:
阅读本文之前,你需要了解:
pom.xml文件如下
<?xml version="1.0" encoding="UTF-8"?> <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/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> <parent> <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> <project.reporting.outputEncoding>UTF-8</project.reporting.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 org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.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"); } @Override 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 org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; import org.springframework.security.oauth2.config.annotation.web.configurers.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("https://www.getpostman.com/oauth2/callback"); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager); } }
这个类是OAuth2认证的核心配置类,在这个类中,配置了OAuth Client的信息,这里有几个地方需要注意:
,它代表了OAuth Client允许认证的类型,其值主要有:
这个配置项接受的类型是个数组,允许配置多个;关于这几种类型的区别,请查看这里不再赘述
redirectUris 关于这个配置项,是在 OAuth2协议中,认证成功后的回调地址,因为稍后我们会使用 Postman 作为测试工具,故此处值固定为 https://www.getpostman.com/oauth2/callback ,此值同样可以配置多个 ResourceServerConfig
package cn.iigrowing.study.oauth2.demo01; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; @Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override public void configure(ResourceServerSecurityConfigurer resources) { resources.resourceId(“users-info”); } @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; } }
注:
资源服务器可以和授权服务器是同一个,也可以分开部署
最后,我们还需添加 application.yml , 配置资源服务器的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: https://github.com/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 状态码。
好了,所有的开发工作已经完成,无需任何其他配置,现在我们启动服务器,并通过 Postman 访问 http://localhost:8043/uaa/users/me
因为现在还没通过认证,所以服务器将返回 401 的状态码,并返回以上的错误信息。
现在我们使用 Postman 来获取 access_token ,首先选择 Authorization Tab, 然后选择 Type 为 OAuth2.0 ,最后点击 Get New Access Token 按钮:
此时将弹出以下界面:
我们填入对应的信息:
此处配置的client相关信息对应了我们在 AuthorizationServerConfig 里面的配置,之前配置的回调地址也来自于此处的 Callback URL 。
接下来点击 Request Token 按钮,在弹出的登陆界面中输入我们之前在 SecurityConfig 中配置的用户信息,选择 Approval 并点击 Authorize 按钮,即可获取 access_token :
到这里我们就成功的获取了 token,此时再次调用 users/me Api,如无意外,将会得到以下的结果:
这个项目实现了以下的功能:
源代码:my.oauth01
小结
OAuth 协议作为一种开放的,基于用户登录的授权认证方式,目前互联网很多 Open API 都对 OAuth 提供了支持,这包括 Google, Yahoo,Twitter 等。本文以 Google 为例子,介绍了 Java 桌面程序如何开发 OAuth 认证应用。在开发桌面应用访问 Web 资源这样一类程序时,一般通行的步骤是:使用 OAuth 做认证,然后使用获得的 OAuth Access Token,通过 REST API 访问用户在服务提供方的资源。
事实上,目前 OAuth 正通过许多实现(包括针对 Java、C#、Objective-C、Perl、PHP 及 Ruby 语言的实现)获得巨大的动力。大部分实现都由 OAuth 项目维护并放在 Google 代码库 (http://oauth.googlecode.com/svn/) 上。开发者可以利用这些 OAuth 类库编写自己需要的 OAuth 应用。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:notice#nhooo.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。