Spring Security OAuth2 Demo —— 密码模式(Password)
前情回顾
前几节分享了OAuth2的流程与授权码模式和隐式授权模式两种的Demo,我们了解到授权码模式是OAuth2四种模式流程最复杂模式,复杂程度由大至小:授权码模式 > 隐式授权模式 > 密码模式 > 客户端模式
其中密码模式的流程是:让用户填写表单提交到授权服务器,表单中包含用户的用户名、密码、客户端的id和密钥的加密串,授权服务器先解析并校验客户端信息,然后校验用户信息,完全通过返回access_token,否则默认都是401 http状态码,提示未授权无法访问
本文目标
编写与说明密码模式的Spring Security Oauth2的demo实现,让未了解过相关知识的读者对此授权流程有个更直观的概念
以下分成授权服务器与资源服务器分别进行解释,只讲关键部分,详情见Github:https://github.com/hellxz/spring-security-oauth2-learn
搭建密码模式授权服务器

代码结构与之前两个模式相同,这里便不再进行说明
SecurityConfig配置
package com.github.hellxz.oauth2.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
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;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.Collections;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("hellxz")
.password(passwordEncoder().encode("xyz"))
.authorities(new ArrayList<>(0));
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//所有请求必须认证
http.authorizeRequests().anyRequest().authenticated();
}
}
基本的SpringSecurity的配置,开启Spring Security的Web安全功能,填了一个用户信息,所有资源必须经过授权才可以访问
AuthorizationConfig授权服务器配置
package com.github.hellxz.oauth2.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
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;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
@Configuration
@EnableAuthorizationServer
public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;//密码模式需要注入认证管理器
@Autowired
public PasswordEncoder passwordEncoder;
//配置客户端
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//@formatter:off
clients.inMemory()
.withClient("client-a")
.secret(passwordEncoder.encode("client-a-secret"))
.authorizedGrantTypes("password") //主要是这里,开始了密码模式
.scopes("read_scope");
//@formatter:on
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);//密码模式必须添加authenticationManager
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients()
.checkTokenAccess("isAuthenticated()");
}
}
这里开启了授权服务器的功能,与上几篇文章中不同的是注入了AuthenticationManager,以及在configure(AuthorizationServerEndpointsConfigurer endpoints)方法中设置了AuthenticationManager
application.properties配置sever.port=8080
搭建资源服务器

这里的关键就是ResourceConfig,配置比较简单与其它几个模式完全一致,模式的不同主要表现在授权服务器与客户端服务器上,资源服务器只做token的校验与给予资源
package com.github.hellxz.oauth2.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
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;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
@Configuration
@EnableResourceServer
public class ResourceConfig extends ResourceServerConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Primary
@Bean
public RemoteTokenServices remoteTokenServices() {
final RemoteTokenServices tokenServices = new RemoteTokenServices();
//设置授权服务器check_token端点完整地址
tokenServices.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token");
//设置客户端id与secret,注意:client_secret值不能使用passwordEncoder加密!
tokenServices.setClientId("client-a");
tokenServices.setClientSecret("client-a-secret");
return tokenServices;
}
@Override
public void configure(HttpSecurity http) throws Exception {
//设置创建session策略
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
//@formatter:off
//所有请求必须授权
http.authorizeRequests()
.anyRequest().authenticated();
//@formatter:on
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId("resource1").stateless(true);
}
}
ResourceController主要接收一个用户名,返回一个username与email的json串

application.properties设置server.port=8081
准备工作到这里就差不多了,开始测试
测试流程
这里客户端使用postman手动发送请求进行演示
访问/oauth/token端点,获取token
http://localhost:8080/oauth/token?username=hellxz&password=xyz&scope=read_scope&grant_type=password
请求头:

请求体:

token返回值
{
"access_token": "4a3c351d-770d-42aa-af39-3f54b50152e9",
"token_type": "bearer",
"expires_in": 43199,
"scope": "read_scope"
}
使用token调用资源,访问http://localhost:8081/user/hellxz001,注意使用token添加Bearer请求头

相当于在Headers中添加 Authorization:Bearer 4a3c351d-770d-42aa-af39-3f54b50152e9
资源正确返回

尾声
本文仅说明密码模式的精简化配置,某些部分如资源服务再访问授权服务去校验token这部分生产环境可能会换成Jwt、Redis等tokenStore实现,授权服务器中的用户信息与客户端信息生产环境应从数据库中读取,对应Spring Security的UserDetailsService实现类或用户信息的Provider等
最近发现博客写得相对较长,一方面有相当大的重复解释代码的部分,另一方面是代码很多不关键的地方也直接全贴出来了,博客长了代码全了,读者容易失去阅读的兴趣与探索实践的欲望。代码不全会直接贴出源码地址,暂时就这样,把这几篇关于OAuth2授权模式demo的文章赶出来
代码早就写完了,下周可能要开始加班了,先把这些已经完成的部分写出来,后续有什么新的知识点才有时间记
Spring Security OAuth2 Demo —— 密码模式(Password)的更多相关文章
- Spring Security OAuth2 Demo —— 客户端模式(ClientCredentials)
前情回顾 前几节分享了OAuth2的流程与其它三种授权模式,这几种授权模式复杂程度由大至小:授权码模式 > 隐式授权模式 > 密码模式 > 客户端模式 本文要讲的是最后一种也是最简单 ...
- Spring Security OAuth2 Demo —— 隐式授权模式(Implicit)
本文可以转载,但请注明出处https://www.cnblogs.com/hellxz/p/oauth2_impilit_pattern.html 写在前面 在文章OAuth 2.0 概念及授权流程梳 ...
- Spring Security OAuth2 Demo
Spring Security OAuth2 Demo 项目使用的是MySql存储, 需要先创建以下表结构: CREATE SCHEMA IF NOT EXISTS `alan-oauth` DEFA ...
- Spring Security OAuth2 Demo —— 授权码模式
本文可以转载,但请注明出处https://www.cnblogs.com/hellxz/p/oauth2_oauthcode_pattern.html 写在前边 在文章OAuth 2.0 概念及授权流 ...
- 使用Spring Security Oauth2完成RESTful服务password认证的过程
摘要:Spring Security与Oauth2整合步骤中详细描述了使用过程,但它对于入门者有些重量级,比如将用户信息.ClientDetails.token存入数据库而非内存.配置 ...
- Spring Security OAuth2 Demo -- good
1. 添加依赖授权服务是基于Spring Security的,因此需要在项目中引入两个依赖: <dependency> <groupId>org.springframework ...
- Spring Security OAuth2 授权码模式
背景: 由于业务实现中涉及到接入第三方系统(app接入有赞商城等),所以涉及到第三方系统需要获取用户信息(用户手机号.姓名等),为了保证用户信息的安全和接入方式的统一, 采用Oauth2四种模式之一 ...
- Spring Security OAuth2 微服务认证中心自定义授权模式扩展以及常见登录认证场景下的应用实战
一. 前言 [APP 移动端]Spring Security OAuth2 手机短信验证码模式 [微信小程序]Spring Security OAuth2 微信授权模式 [管理系统]Spring Se ...
- Spring Security 解析(五) —— Spring Security Oauth2 开发
Spring Security 解析(五) -- Spring Security Oauth2 开发 在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因此决 ...
随机推荐
- Jetpack Compse 实战 —— 全新的开发体验
公众号回复 Compose 获取安装包 项目地址: Wanandroid-Compose 经过前段时间的 Android Dev Summit ,相信你已经大概了解了 Jetpack Compose ...
- 云服务器linux系统修改时间和时区
申请的云服务器时间不对,用同步网络时间的命令执行后依然有问题. 解决办法: # tzselect [root@ylyuat2-web02 logs]# TZ='Asia/Shanghai'[root@ ...
- 理解clientWidth,offsetWidth,clientLeft,offsetLeft,clientX,offsetX,pageX,screenX
1. clientWidth:表示元素的内部宽度,以像素计.该属性包括内边距,但不包括垂直滚动条(如果有).边框和外边距.(clientWidth = width + padding) 2. offs ...
- Salesforce学习之路(十)Org的命名空间
1. 命名空间的适用场景 每个组件都是命名空间的一部分,如果Org中设置了命名空间前缀,那么需使用该命名空间访问组件.否则,使用默认命名空间访问组件,系统默认的命名空间为“c”. 如果Org没有创建命 ...
- 关于RAID 5的介绍与创建
一.简介 定义: RAID 5是RAID 0和RAID 1的折中方案.RAID 5具有和RAID0相近似的数据读取速度,只是多了一个奇偶校验信息,写入数据的速度比对单个磁盘进行写入操作稍慢.同时由于多 ...
- [apue] FIFO:不是文件的文件
众所周知,FIFO中文译为命名管道,是PIPE的升级版.而PIPE是管道,系统提供的一种进程间通讯方式,FIFO与PIPE有以下方面不同: 1) FIFO需要先在文件系统创建(mkfifo),之后使用 ...
- Java基础知识总结之多线程
1.基本概念 进程是程序的一次动态执行过程,是系统进行资源分配和调度运行的基本单位. 线程是进程的一个实体,它是比进程更小的的能够独立运行的基本单位.在引入线程的操作系统中,通常都是把进程作为分配资源 ...
- 2019-9-9:渗透测试,docker下载dvwa,使用报错型sql注入dvwa
docker下载dvwa镜像,报错型注入dvwa,low级 一,安装并配置docker 1,更新源,apt-get update && apt-get upgrade &&am ...
- C# 异步并发操作,只保留最后一次操作
在我们业务操作时,难免会有多次操作,我们期望什么结果呢? 绝大部分情况,应该是只需要最后一次操作的结果,其它操作应该无效. 自定义等待的任务类 1. 可等待的任务类 AwaitableTask: // ...
- 深入浅出Spring(二)
IoC概念 控制反转(Inversion of Control)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题. 它还有一个名字叫做依赖注入(Dependency Injection).Io ...