Spring Security Oauth2 示例
所有示例的依赖如下(均是SpringBoot项目)
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
</dependency>
</dependencies>
一、ResourceServer(资源服务器)
application.yml
server:
port: 8082
context-path: /resourceserver
启动类
@SpringBootApplication
public class ResourceServerApplication {
public static void main(String[] args) {
SpringApplication.run(ResourceServerApplication.class, args);
}
}
TestController.java(暴露RESTful接口)
@RestController
public class TestController {
@GetMapping("/product/{id}")
public String product(@PathVariable String id) {
return "product id : " + id;
}
@GetMapping("/order/{id}")
public String order(@PathVariable String id) {
return "order id : " + id;
}
@GetMapping("/pomer/{id}")
public String pomer(@PathVariable String id) {
return "pomer id : " + id;
}
}
配置类 ResourceServerConfig(配置JWT形式的token)
@EnableResourceServer
@Configuration
public class ResourceServerConfig {
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("123");
return converter;
}
}
配置类 MyResourceServerConfigurer(配置访问权限)
@Configuration
public class MyResourceServerConfigurer extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/product/**").permitAll()
.antMatchers("/order/**").authenticated()
.antMatchers("/pomer/**").access("#oauth2.hasScope('read_profile') and hasAuthority('ADMIN')");
}
}
二、AuthorizationServer 授权服务器(授权码模式,authorization code)
application.yml
server:
port: 8081
context-path: /authorizationserver
启动类
@SpringBootApplication
public class AuthorizationServerApplication {
public static void main(String[] args) {
SpringApplication.run(AuthorizationServerApplication.class, args);
}
}
配置类 AuthorizationServerConfig(配置JWT形式的token)
@EnableAuthorizationServer
@Configuration
public class AuthorizationServerConfig {
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("123");
return converter;
}
}
配置类 MyAuthorizationServerConfigurer
@Configuration
public class MyAuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private TokenStore tokenStore;
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore)
.accessTokenConverter(jwtAccessTokenConverter)
.authenticationManager(authenticationManager);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("clientApp")
.secret("123456")
.redirectUris("http://localhost:9000/callback")
.authorizedGrantTypes("authorization_code")
.scopes("read_profile", "read_contacts");
}
}
配置类 MyWebSecurityConfigurerAdapter(配置用户名密码)
@Configuration
public class MyWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("123456").authorities("USER").and()
.withUser("admin").password("123456").authorities("USER", "ADMIN");
}
}
开始测试!打开浏览器访问:
http://localhost:8081/authorizationserver/oauth/authorize?client_id=clientApp&redirect_uri=http://localhost:9000/callback&response_type=code&scope=read_profile
显示登录页面,输入用户名密码,返回重定向302(授权码位于参数部分)
http://localhost:9000/callback?code=EWfpi5
根据授权码,请求令牌:
> curl -X POST --user clientApp:123456 http://localhost:8081/authorizationserver/oauth/token -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=authorization_code&redirect_uri=http://localhost:9000/callback&scope=read_profile&code=EWfpi5"
# clientApp:123456 经Base64编码得 'Y2xpZW50QXBwOjEyMzQ1Ng=='
POST /authorizationserver/oauth/token HTTP/1.1
Host: localhost:8081
Content-Type: application/x-www-form-urlencoded
Authorization: Basic Y2xpZW50QXBwOjEyMzQ1Ng==
Cache-Control: no-cache
Postman-Token: c6c182c7-5df1-46ea-9cb7-130ff250c93c
code=F4QesT&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A9000%2Fcallback&scope=read_profile
得到令牌:
{
"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDE4NTExMTYsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJVU0VSIl0sImp0aSI6ImMyYzQ4YTc0LWI4MjUtNGNlYS05NGU3LTMyM2VlN2Q4NTk2ZCIsImNsaWVudF9pZCI6ImNsaWVudEFwcCIsInNjb3BlIjpbInJlYWRfcHJvZmlsZSJdfQ.Oc1TN7fMPgNVXX7k8dEw0QqosD7ZKQ198c-Qa2l1Gho",
"token_type":"bearer",
"expires_in":43199,
"scope":"read_profile",
"jti":"c2c48a74-b825-4cea-94e7-323ee7d8596d"
}
根据令牌请求资源
> curl http://localhost:8082/resourceserver/order/12 -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDE4NTExMTYsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJVU0VSIl0sImp0aSI6ImMyYzQ4YTc0LWI4MjUtNGNlYS05NGU3LTMyM2VlN2Q4NTk2ZCIsImNsaWVudF9pZCI6ImNsaWVudEFwcCIsInNjb3BlIjpbInJlYWRfcHJvZmlsZSJdfQ.Oc1TN7fMPgNVXX7k8dEw0QqosD7ZKQ198c-Qa2l1Gho"
GET /resourceserver/order/12 HTTP/1.1
Host: localhost:8082
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDE4NTExMTYsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJVU0VSIl0sImp0aSI6ImMyYzQ4YTc0LWI4MjUtNGNlYS05NGU3LTMyM2VlN2Q4NTk2ZCIsImNsaWVudF9pZCI6ImNsaWVudEFwcCIsInNjb3BlIjpbInJlYWRfcHJvZmlsZSJdfQ.Oc1TN7fMPgNVXX7k8dEw0QqosD7ZKQ198c-Qa2l1Gho
Cache-Control: no-cache
Postman-Token: 913a8844-1308-47d8-afa3-a9f288323c20
返回资源
order id : 12
附:/product/* 允许任何人访问,/order/* 需要用户认证,而 /pomer/* 只允许拥有ADMIN权限的admin用户访问,测试有效
三、AuthorizationServer 授权服务器(简化模式,implicit)
只修改配置类 MyAuthorizationServerConfigurer,其余代码不变
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("clientApp")
.secret("123456")
.redirectUris("http://localhost:9000/callback")
.authorizedGrantTypes("implicit")
.scopes("read_profile","read_contacts");
}
开始测试!打开浏览器访问:
http://localhost:8081/authorizationserver/oauth/authorize?client_id=clientApp&redirect_uri=http://localhost:9000/callback&response_type=token&scope=read_profile&state=xyz
显示登录页面,输入用户名密码,返回重定向302(令牌位于hash部分):
http://localhost:9000/callback#access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDE4NjMxNjMsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJVU0VSIl0sImp0aSI6ImQ2MzYxYzZjLTIyZWYtNDU2ZC1iOGJhLWY4ZTE5MzMwMTBmOSIsImNsaWVudF9pZCI6ImNsaWVudEFwcCIsInNjb3BlIjpbInJlYWRfcHJvZmlsZSJdfQ.BRwtzF2rFc6w8WECqYETZbkCSDdoOzKdF4Zm_SAZuao&token_type=bearer&state=xyz&expires_in=119&jti=d6361c6c-22ef-456d-b8ba-f8e1933010f9
得到令牌,后续请求资源相同,不再重复叙述
四、AuthorizationServer 授权服务器(密码模式,resource owner password credentials)
修改配置类 MyAuthorizationServerConfigurer
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("clientApp")
.secret("123456")
.authorizedGrantTypes("password")
.scopes("read_profile", "read_contacts");
}
在默认情况下 AuthorizationServerEndpointsConfigurer 配置没有开启密码模式,只有配置了 authenticationManager 才会开启密码模式,如下
在 MyWebSecurityConfigurerAdapter.java 新增一段代码(配置 authenticationManager Bean)
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
在 MyAuthorizationServerConfigurer.java 新增一段代码(令 AuthorizationServerEndpointsConfigurer 设置 authenticationManager)
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private TokenStore tokenStore;
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.tokenStore(tokenStore)
.accessTokenConverter(jwtAccessTokenConverter)
.authenticationManager(authenticationManager);
}
开始测试!请求令牌
> curl -X POST --user clientApp:123456 http://localhost:8081/authorizationserver/oauth/token -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=password&scope=read_profile&username=user&password=123456"
得到令牌:
{
"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDE5MDk4MTcsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJVU0VSIl0sImp0aSI6ImJhZDk1OTI0LTdkYTgtNDUyMy05YzZkLTBkNzY3NTlmYjQ1NiIsImNsaWVudF9pZCI6ImNsaWVudEFwcCIsInNjb3BlIjpbInJlYWRfcHJvZmlsZSJdfQ.gO5_kl8_OBRnj2Dt5glflXAIJrbyioYXezV-ZQ8BxL4",
"token_type":"bearer",
"expires_in":43199,
"scope":"read_profile",
"jti":"bad95924-7da8-4523-9c6d-0d76759fb456"
}
得到令牌,后续请求资源相同,不再重复叙述
五、AuthorizationServer 授权服务器(客户端模式,client credentials)
只修改配置类 MyAuthorizationServerConfigurer,其余代码不变
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("clientApp")
.secret("123456")
.authorizedGrantTypes("client_credentials")
.scopes("read_profile", "read_contacts");
}
开始测试!请求令牌
> curl -X POST --user clientApp:123456 http://localhost:8081/authorizationserver/oauth/token -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=client_credentials&scope=read_profile"
得到令牌:
{
"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6WyJyZWFkX3Byb2ZpbGUiXSwiZXhwIjoxNTQxOTEwOTEzLCJqdGkiOiI5MDVjNzc2OS1lNGQ2LTQxYTItYjcyMC1jYzliZWZjYzE5MDQiLCJjbGllbnRfaWQiOiJjbGllbnRBcHAifQ.c6UiHxbCdioCklkCqkLsCG6C8KHwwzajlPka6ut5MJs",
"token_type":"bearer",
"expires_in":43199,
"scope":"read_profile",
"jti":"905c7769-e4d6-41a2-b720-cc9befcc1904"
}
得到令牌,后续请求资源相同,不再重复叙述
Spring Security Oauth2 示例的更多相关文章
- 使用Spring Security Oauth2完成RESTful服务password认证的过程
摘要:Spring Security与Oauth2整合步骤中详细描述了使用过程,但它对于入门者有些重量级,比如将用户信息.ClientDetails.token存入数据库而非内存.配置 ...
- Spring Security OAuth2 SSO
通常公司肯定不止一个系统,每个系统都需要进行认证和权限控制,不可能每个每个系统都自己去写,这个时候需要把登录单独提出来 登录和授权是统一的 业务系统该怎么写还怎么写 最近学习了一下Spring Sec ...
- Spring Security Oauth2 单点登录案例实现和执行流程剖析
Spring Security Oauth2 OAuth是一个关于授权的开放网络标准,在全世界得到的广泛的应用,目前是2.0的版本.OAuth2在“客户端”与“服务提供商”之间,设置了一个授权层(au ...
- Spring Security OAuth2实现单点登录
1.概述 在本教程中,我们将讨论如何使用 Spring Security OAuth 和 Spring Boot 实现 SSO(单点登录). 本示例将使用到三个独立应用 一个授权服务器(中央认证机制) ...
- Re:从零开始的Spring Security Oauth2(一)
前言 今天来聊聊一个接口对接的场景,A厂家有一套HTTP接口需要提供给B厂家使用,由于是外网环境,所以需要有一套安全机制保障,这个时候oauth2就可以作为一个方案. 关于oauth2,其实是一个规范 ...
- 使用Spring Security OAuth2进行简单的单点登录
1.概述 在本教程中,我们将讨论如何使用Spring Security OAuth和Spring Boot实现SSO - 单点登录. 我们将使用三个单独的应用程序: 授权服务器 - 这是中央身份验证机 ...
- 一文带你了解 OAuth2 协议与 Spring Security OAuth2 集成!
OAuth 2.0 允许第三方应用程序访问受限的HTTP资源的授权协议,像平常大家使用Github.Google账号来登陆其他系统时使用的就是 OAuth 2.0 授权框架,下图就是使用Github账 ...
- spring security oauth2搭建resource-server demo及token改造成JWT令牌
我们在上文讲了如何在spring security的环境中搭建基于oauth2协议的认证中心demo:https://www.cnblogs.com/process-h/p/15688971.html ...
- 【OAuth2.0】Spring Security OAuth2.0篇之初识
不吐不快 因为项目需求开始接触OAuth2.0授权协议.断断续续接触了有两周左右的时间.不得不吐槽的,依然是自己的学习习惯问题,总是着急想了解一切,习惯性地钻牛角尖去理解小的细节,而不是从宏观上去掌握 ...
随机推荐
- 28.实现 strStr() 函数
28.实现 strStr() 函数 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始).如果不存在, ...
- Senparc.Weixin.MP SDK 微信公众平台开发教程(十九):MessageHandler 的未知类型消息处理
这是<微信开发深度解析:微信公众号.小程序高效开发秘籍>出版之后写的第一篇微信相关的文章.从这一篇开始,将介绍第一版出版之后添加或修改的功能,或者对书上内容需要做的补充. MP v14.8 ...
- 技术干货:实时视频直播首屏耗时400ms内的优化实践
本文由“逆流的鱼yuiop”原创分享于“何俊林”公众号,感谢作者的无私分享. 1.引言 直播行业的竞争越来越激烈,进过2018年这波洗牌后,已经度过了蛮荒暴力期,剩下的都是在不断追求体验.最近正好在做 ...
- 常见的anaconda的操作
以前对anaconda的理解比较少,以为它就是一个比较大的python库,现在发现它原来不止是这样,它还有很多其他用途. Anaconda指的是一个开源的Python发行版本,其包含了conda.Py ...
- Python档案袋( 时间 和 随机数 模块 )
时间模块 #导入必要模块 import time #获取时间戳 print(time.time()) #输出:1547651016.03502 #格式化时间元组 # 参数可传递自定义的时间戳,如:ti ...
- Kaazing Gateway简单使用
Kaazing GateWay是一种提供跨平台跨浏览器WebSocket支持的网关,由Java编写,介绍一下Kaazing GateWay的安装配置和简单使用,哪里说得不对,还请指出. 1. 安装 a ...
- sql server 索引阐述系列二 索引存储结构
一.概述. "流光容易把人抛,红了樱桃,绿了芭蕉“ 转眼又年中了,感叹生命的有限,知识的无限.在后续讨论索引之前,先来了解下索引和表数据的内部结构,这一节将介绍页的存储,页分配单元类型,区的 ...
- Linux文件系统及文件属性
一.Linux文件系统 1.穿件文件系统 Linux中当磁盘格式化创建文件系统时,会创建一定数量的节点索引Inode以及一定数量的块block,其中inode具有存储文件属性以及指向文件实体block ...
- 基本排序算法Golang
摘要 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 冒泡排序 func BubbleSort(ve ...
- Thrown "KeeperErrorCode = Unimplemented for /services" exception
1.环境 spring-boot 2.1.3 依赖项:spring-cloud-starter-zookeeper-discovery 版本2.1.1 使用的zookeeper3.4.11 代码如下: ...