Oauth2认证模式之授权码模式(authorization code)

本示例实现了Oauth2之授权码模式,授权码模式(authorization code)是功能最完整、流程最严密的授权模式。它的特点就是通过客户端的后台服务器,与"服务提供商"的认证服务器进行互动。

阅读本示例之前,你需要先有以下两点基础:

  • 需要对spring security有一定的配置使用经验,用户认证这一块,spring security oauth2建立在spring security的基础之上
  • oauth2开放授权标准基础,可以稳步到OAuth2 详解,浏览下授权码模式,理解下基本概念

概述

实现 oauth2,可以简易的分为三个步骤

  • 配置资源服务器
  • 配置认证服务器
  • 配置spring security

代码实现

1.pom.xml添加maven依赖

    <dependencies>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>

2.配置资源服务器

public class ResourceServerConfig {

    private static final String RESOURCE_ID = "account";

    @Configuration
@EnableResourceServer()
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter { @Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID).stateless(true);
} @Override
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.requestMatchers()
// 保险起见,防止被主过滤器链路拦截
.antMatchers("/account/**").and()
.authorizeRequests().anyRequest().authenticated()
.and()
.authorizeRequests()
.antMatchers("/account/info/**").access("#oauth2.hasScope('get_user_info')")
.antMatchers("/account/child/**").access("#oauth2.hasScope('get_childlist')");
}
}
}

3.配置认证服务器

    @Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client1")
.resourceIds(RESOURCE_ID)
.authorizedGrantTypes("authorization_code", "refresh_token", "implicit")
.authorities("ROLE_CLIENT")
.scopes("get_user_info", "get_childlist")
.secret("secret")
.redirectUris("http://localhost:8081/client/account/redirect")
.autoApprove(true)
.autoApprove("get_user_info");
}

4.配置spring security

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean
@Override
protected UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
// 创建两个内存用户
manager.createUser(User.withUsername("admin").password("123456").authorities("USER").build());
manager.createUser(User.withUsername("lin").password("123456").authorities("USER").build());
return manager;
} @Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
} @Bean
PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
} /**
* 密码生成器(默认为bcrypt模式)
*
* @return
*/
// @Bean
// PasswordEncoder passwordEncoder() {
// return PasswordEncoderFactories.createDelegatingPasswordEncoder();
// } @Override
protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity.
requestMatchers()
// 必须登录过的用户才可以进行 oauth2 的授权码申请
.antMatchers("/", "/home", "/login", "/oauth/authorize")
.and()
.authorizeRequests()
.anyRequest().permitAll()
.and()
.formLogin()
.loginPage("/login")
.and()
.httpBasic()
.disable()
.exceptionHandling()
.accessDeniedPage("/login?authorization_error=true")
.and()
.csrf()
.requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize"))
.disable();
}
}

使用介绍

  • 找到AuthResServerApplication.java运行server服务,默认端口:8080
  • 找到ClientApplication.java运行client客户端,端口:8081

1.尝试直接访问用户信息

http://localhost:8080/account/info/testAccount1/

返回未授权错误

<oauth>
<error_description>
Full authentication is required to access this resource
</error_description>
<error>unauthorized</error>
</oauth>

2.尝试获取授权码

http://localhost:8080/oauth/authorize?client_id=client1&response_type=code&redirect_uri=http://localhost:8081/client/account/redirect

结果被主过滤器拦截,302 跳转到登录页,因为 /oauth/authorize 端点是受保护的端点,必须登录的用户才能申请 code。

3.输入用户名和密码

输入用户名和密码 admin 123456

如上用户名密码是交给 SpringSecurity 的主过滤器用来认证的

4.登录成功后,真正进行授权码的申请

oauth/authorize 认证成功,会根据 redirect_uri 执行 302 重定向,并且带上生成的 code,注意重定向到的是 8001 端口,这个时候已经是另外一个应用了。

localhost:8081/client/account/redirect?code=xxxx

代码中封装了一个 http 请求,使得 client1 使用 restTemplate 向 server 发送 token 的申请,当然是使用 code 来申请的,并最终成功获取到 access_token

{
access_token: "59a25558-f714-4ca8-aa87-c36f93c120bf",
token_type: "bearer",
refresh_token: "92436849-7ef7-4923-8270-5a2c9b464556",
expires_in: 43199,
scope: "get_user_info get_childlist"
}

5.携带 access_token 访问account信息

http://localhost:8080/account/info/testAccount1?access_token=59a25558-f714-4ca8-aa87-c36f93c120bf

6.正常返回信息

{
name: "testAccount1",
nickName: "测试用户1",
remark: "备注1",
childAccount: [
{
name: "testChild1_0",
nickName: "测试子用户1_0",
remark: "0",
childAccount: null
},
{
name: "testChild1_1",
nickName: "测试子用户1_1",
remark: "1",
childAccount: null
},
{
name: "testChild1_2",
nickName: "测试子用户1_2",
remark: "2",
childAccount: null
},
{
name: "testChild1_3",
nickName: "测试子用户1_3",
remark: "3",
childAccount: null
},
{
name: "testChild1_4",
nickName: "测试子用户1_4",
remark: "4",
childAccount: null
},
{
name: "testChild1_5",
nickName: "测试子用户1_5",
remark: "5",
childAccount: null
},
{
name: "testChild1_6",
nickName: "测试子用户1_6",
remark: "6",
childAccount: null
},
{
name: "testChild1_7",
nickName: "测试子用户1_7",
remark: "7",
childAccount: null
},
{
name: "testChild1_8",
nickName: "测试子用户1_8",
remark: "8",
childAccount: null
},
{
name: "testChild1_9",
nickName: "测试子用户1_9",
remark: "9",
childAccount: null
}
]
}

资料

Oauth2认证模式之授权码模式实现的更多相关文章

  1. IdentityServer4实现OAuth2.0四种模式之授权码模式

    接上一篇:IdentityServer4实现OAuth2.0四种模式之隐藏模式 授权码模式隐藏码模式最大不同是授权码模式不直接返回token,而是先返回一个授权码,然后再根据这个授权码去请求token ...

  2. Owin + WebApi + OAuth2 搭建授权模式(授权码模式 Part I)

    绪 最近想要整理自己代码封装成库,也十分想把自己的设计思路贴出来让大家指正,奈何时间真的不随人意. 想要使用 OWIN 做中间件服务,该服务中包含 管线.授权 两部分.于是决定使用 webapi .O ...

  3. Oauth2.0认证---授权码模式

    目录: 1.功能描述 2.客户端的授权模式 3.授权模式认证流程 4.代码实现 1.功能描述 OAuth在"客户端"与"服务提供商"之间,设置了一个授权层(au ...

  4. oauth2.0授权码模式详解

    授权码模式原理 授权码模式(authorization code)是功能最完整.流程最严密的授权模式.它的特点就是通过客户端的后台服务器,与"服务提供商"的认证服务器进行互动. 它 ...

  5. 微信授权就是这个原理,Spring Cloud OAuth2 授权码模式

    上一篇文章Spring Cloud OAuth2 实现单点登录介绍了使用 password 模式进行身份认证和单点登录.本篇介绍 Spring Cloud OAuth2 的另外一种授权模式-授权码模式 ...

  6. 阶段5 3.微服务项目【学成在线】_day16 Spring Security Oauth2_06-SpringSecurityOauth2研究-Oauth2授权码模式-申请令牌

    3.3 Oauth2授权码模式 3.3.1 Oauth2授权模式 Oauth2有以下授权模式: 授权码模式(Authorization Code) 隐式授权模式(Implicit) 密码模式(Reso ...

  7. IdentityServer4系列 | 授权码模式

    一.前言 在上一篇关于简化模式中,通过客户端以浏览器的形式请求IdentityServer服务获取访问令牌,从而请求获取受保护的资源,但由于token携带在url中,安全性方面不能保证.因此,我们可以 ...

  8. 基于OWIN WebAPI 使用OAUTH2授权服务【授权码模式(Authorization Code)】

    之前已经简单实现了OAUTH2的授权码模式(Authorization Code),但是基于JAVA的,今天花了点时间调试了OWIN的实现,基本就把基于OWIN的OAUHT2的四种模式实现完了.官方推 ...

  9. 学习Spring Security OAuth认证(一)-授权码模式

    一.环境 spring boot+spring security+idea+maven+mybatis 主要是spring security 二.依赖 <dependency> <g ...

随机推荐

  1. spring的context:exclude-filter 与 context:include-filter

    1 在主容器中(applicationContext.xml),将Controller的注解打消掉 <context:component-scan base-package="com& ...

  2. 网络下载器 迅雷大众版 v7.9.42.5050 精简绿色版

    下载地址:点我 基本介绍 迅雷大众版是一款采用了先进的超线程技术基于网格原理,能够将存在于第三方服务器和计算机上的数据文件进行有效整合,通过这种先进的超线程技术,用户能够以更快的速度从这些第三方节点平 ...

  3. ~~核心编程(四):面向对象——单继承&复写~~

    进击のpython 继承 继承的出现!就是一个作用! 为了节省代码! 为什么说节省代码? 你爸爸要是王健林 你是不是就不用愁怎么获得钱了? 为啥? 是不是钱已经有了! 直接拿来用就行了! 我们想一下奥 ...

  4. Java编程思想:擦除的神秘之处

    import java.lang.reflect.Array; import java.util.ArrayList; import java.util.List; public class Test ...

  5. USACO-修理牛棚

    #include<cstdio> #include<algorithm> using namespace std; int a[201],b[201]; int main() ...

  6. Orleans 知多少 | 2. 核心概念一览

    Orleans 术语解读 上面这张图中包含了Orleans中的几个核心概念: Grain Silo Orleans Cluster Orleans Client 从这张图,我们应该能理清他们之间的关系 ...

  7. ASP.NET Core MVC 之视图(Views)

    ASP.NET Core MVC 控制器可以使用视图返回格式化的结果. 1.什么是视图 在 MVC 中,视图封装了用户与应用交互呈现细节.视图是具有生成要发送到客户端内容的,包含嵌入代码的HTML模板 ...

  8. [剑指offer] 23. 二叉搜索树的后序遍历序列

    题目描述 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. 思路: 解法一:递归 二叉搜索树,后序遍历的数组中 ...

  9. Linux系统安装Tomcat——.tar.gz版(old)

    这里简单地阐述一下rpm.deb.tar.gz的区别. rpm格式的软件包适用于基于Red Hat发行版的系统,如Red Hat Linux.SUSE.Fedora. deb格式的软件包则是适用于基于 ...

  10. junit的Test不能使用,报错信息:Test is not an annotation type

    在使用junit的Test做测试时,注解@Test报错”Test is not an annotation type”,发现是因为测试类的类名命名为了Test,所以导致错误. 测试类类名不能直接命名为 ...