Spring security oauth2 password flow
Spring security oauth2 包含以下两个endpoint来实现Authorization Server:
AuthorizationEndpoint: 授权请求访问端点, 默认url: /oauth/authorize
TokenEndpoint: 获取access token的请求的访问端点, 默认url: /oauth/token
添加依赖
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
配置Authorization Server
@EnableAuthprizationServer注解, 配合实现了AuthorizationServerConfigurer的配置类来配置Authorization Server。
AuthorizationServerConfigurer中主要的配置有三个, 覆盖对应的方法即可:
ClientDetailsServiceConfigurer:
定义了client detail service, 可以简单的指定几个client, 或者指向数据库中的表。
可以存储client信息到内存中或数据库中, 即in-memory和JDBC两种实现。
AuthorizationServerSecurityConfigurer:
定义了token端点的安全策略
其中有两个重要的端点:
/oauth/check_token: 检查token的有效性
/oauth/token_key: 获取token的key
AuthorizationServerEndpointsConfigurer:
定义authorization endpoint, token endpoint以及token service。token service管理token相关的一切, 除了token的持久化是委托给TokenStore来实现, 默认的实现是DefaultTokenServices.
有三种类型的TokenStore:
InMemoryTokenStore: 默认实现, 存储在内存中。
JdbcTokenStore: token数据存储在关系型数据库中。
JWT 类型的TokenStore, 典型的是JwtTokenStore, 不存储到任何地方, 把所有的数据编码到token中, 因此token的撤回(revoke)实现起来优点麻烦。
配置:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
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;
import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import java.util.Arrays;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Value("${security.oauth2.client.client-id}")
private String clientId;
@Value("${security.oauth2.client.client-secret}")
private String clientCredentials;
private final PasswordEncoder passwordEncoder;
private final AuthenticationManager authenticationManager;
private final DefaultTokenEnhancer defaultTokenEnhancer;
private final UserDetailsService userDetailsService;
@Autowired
public AuthorizationServerConfig(PasswordEncoder passwordEncoder, AuthenticationManager authenticationManager,
DefaultTokenEnhancer defaultTokenEnhancer,
UserDetailsService userDetailsService) {
this.passwordEncoder = passwordEncoder;
this.authenticationManager = authenticationManager;
this.defaultTokenEnhancer = defaultTokenEnhancer;
this.userDetailsService = userDetailsService;
}
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
configurer
.inMemory()
.withClient(clientId)
.secret(passwordEncoder.encode(clientCredentials))
.authorizedGrantTypes("password", "refresh_token")
.accessTokenValiditySeconds(3600);
}
@Override
public void configure(final AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()")
.allowFormAuthenticationForClients(); // 默认通过basic authentication, 即加一个header为Authorization: Basic base64(username:password), 指定这个可以设置form提交, 把client-id, client-secret放到post参数中。
}
@Bean
TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter jwtConverter = new JwtAccessTokenConverter();
jwtConverter.setSigningKey("your-sign-key");
return jwtConverter;
}
@Bean
public WebResponseExceptionTranslator loggingExceptionTranslator() {
return new DefaultWebResponseExceptionTranslator() {
@Override
public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception {
e.printStackTrace();
ResponseEntity<OAuth2Exception> responseEntity = super.translate(e);
HttpHeaders headers = new HttpHeaders();
headers.setAll(responseEntity.getHeaders().toSingleValueMap());
OAuth2Exception excBody = responseEntity.getBody();
return new ResponseEntity<>(excBody, headers, responseEntity.getStatusCode());
}
};
}
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(defaultTokenEnhancer, jwtAccessTokenConverter()));
endpoints.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService)
.tokenStore(tokenStore())
.tokenEnhancer(tokenEnhancerChain)
.exceptionTranslator(loggingExceptionTranslator());
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
@Order(1)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(10);
}
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return this.authenticationManager();
}
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin().permitAll()
.and()
.csrf().disable()
.cors().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.antMatchers("/oauth/**").permitAll()
.anyRequest().authenticated();
}
}
formLogin().permitAll()对password flow不是必须的, 只对implicit flow有影响。
当时测试implicit flow的时候确实是这样, 在访问/oauth/authorize之后, 需要登录, 登录后一直提示错误, 但没有错误信息, 从而获取不到token, 加了formLogin().permitAll()选项后就正常返回token了。
获取access token:
访问地址: POST localhost:8080/oauth/token
参数:client_id=clientId&client_secret=clientSecret&grant_type=password&username=username&password=password
刷新access token:
POST localhost:8080/oauth/token
参数:
client_id=clientId&client_secret=clientSecret&grant_type=refresh_token&scope=any&refresh_token=refreshToken
顺便介绍一下其他的grant type:
grant type授权类型一般有client credentials, password, implicit, authorization code, refresh。
client credentials是直接访问/oauth/token端点带grant_type
password 访问/oauth/token端点带grant_type
implicit 访问/oauth/authorize端点带response_type参数, 值为token, 然后会直接重定向到你指定的redirect_uri, url中带access_token参数
authorize code 先访问/oauth/authorize端点带response_type参数, 值为code, 然后它会返回一个code参数; 带上code参数访问/oauth/token端点获取access token。
refer:
https://www.baeldung.com/rest-api-spring-oauth2-angular
https://dzone.com/articles/spring-boot-oauth2-getting-the-authorization-code
https://walkingtree.tech/securing-microservices-oauth2/
https://projects.spring.io/spring-security-oauth/docs/oauth2.html
Spring security oauth2 password flow的更多相关文章
- 转 - spring security oauth2 password授权模式
原贴地址: https://segmentfault.com/a/1190000012260914#articleHeader6 序 前面的一篇文章讲了spring security oauth2的c ...
- 使用Spring Security Oauth2完成RESTful服务password认证的过程
摘要:Spring Security与Oauth2整合步骤中详细描述了使用过程,但它对于入门者有些重量级,比如将用户信息.ClientDetails.token存入数据库而非内存.配置 ...
- springboot+spring security +oauth2.0 demo搭建(password模式)(认证授权端与资源服务端分离的形式)
项目security_simple(认证授权项目) 1.新建springboot项目 这儿选择springboot版本我选择的是2.0.6 点击finish后完成项目的创建 2.引入maven依赖 ...
- Spring Security OAuth2 Demo —— 密码模式(Password)
前情回顾 前几节分享了OAuth2的流程与授权码模式和隐式授权模式两种的Demo,我们了解到授权码模式是OAuth2四种模式流程最复杂模式,复杂程度由大至小:授权码模式 > 隐式授权模式 > ...
- Spring Security Oauth2 的配置
使用oauth2保护你的应用,可以分为简易的分为三个步骤 配置资源服务器 配置认证服务器 配置spring security 前两点是oauth2的主体内容,但前面我已经描述过了,spring sec ...
- Re:从零开始的Spring Security Oauth2(一)
前言 今天来聊聊一个接口对接的场景,A厂家有一套HTTP接口需要提供给B厂家使用,由于是外网环境,所以需要有一套安全机制保障,这个时候oauth2就可以作为一个方案. 关于oauth2,其实是一个规范 ...
- Spring Security OAuth2.0认证授权五:用户信息扩展到jwt
历史文章 Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授权二:搭建资源服务 Spring Security OA ...
- 【OAuth2.0】Spring Security OAuth2.0篇之初识
不吐不快 因为项目需求开始接触OAuth2.0授权协议.断断续续接触了有两周左右的时间.不得不吐槽的,依然是自己的学习习惯问题,总是着急想了解一切,习惯性地钻牛角尖去理解小的细节,而不是从宏观上去掌握 ...
- Spring security oauth2最简单入门环境搭建
关于OAuth2的一些简介,见我的上篇blog:http://wwwcomy.iteye.com/blog/2229889 PS:貌似内容太水直接被鹳狸猿干沉.. 友情提示 学习曲线:spring+s ...
随机推荐
- Sam小结和模板
Sam 的一些总结 注意在子串在某个节点的性质,其 father 上也会有相同的性质 1. 统计子串出现的次数 在 \(parent\) 树上做 \(dp\),对于每一个节点,初始化为 \(dp[i] ...
- 在调试时,有什么更好的方法可以监视最后一个win32错误?
我发现在代码中使用win32api时,需要多次监视最后一个win32错误!(在每次使用API后调用GetLastError()是不可行的解决方案!).. 在Visual Studio中,它们提供了一个 ...
- CF 852E Casinos and travel
题目链接 \(Desccription\) 给定一棵树,John从任意一个点开始,每次走向一个未到达过的点.每个点都可以有或没有赌场,每经过一个赌场心情都会反转,旅行开始前心情很好. 问有多少种方案使 ...
- 洛谷p3398仓鼠找suger题解
我现在爱死树链剖分了 题目 具体分析的话在洛谷blog里 这里只是想放一下改完之后的代码 多了一个son数组少了一个for 少了找size最大的儿子的for #include <cstdio&g ...
- svn报错:[Previous operation has not finished; run 'cleanup' if it was interrupted] 的排错过程
今天在打开某一文档的情况下,使用SVN更新文档,在更新的过程中报错,提示需要执行clean up,果断右键执行clean up,又提示一个新的错误:"Previous operation h ...
- LINK : fatal error LNK1181: cannot open input file 'glew32.lib' error: command 'C:\\Program Files (
下载 库文件 参考: https://stackoverflow.com/questions/53355474/kivent-installation-fatal-error-lnk1181-cant ...
- dedecms复制网上的带有图片的文章,图片不能自动下载到本地的解决方法
dede有时看到比较好的文章需要复制,粘贴到自己的dede后台发布,dede是有图片自动本地化的功能,就是复制过来后自动下载到你的服务器上了,这样省去了你单独去另存图片再上传的过程,尤其是遇到有很多图 ...
- 代码审计和动态测试——BUUCTF - 高明的黑客
根据题目提示,访问http://2ea746a2-0ecd-449b-896b-e0fb38956134.node1.buuoj.cn/www.tar.gz下载源码 解压之后发现有3002个php文件 ...
- 一分钟理解什么是REST和RESTful
从事web开发工作有一小段时间,REST风格的接口,这样的词汇总是出现在耳边,然后又没有完全的理解,您是不是有和我相同的疑问呢?那我们一起来一探究竟吧! 就是用URL定位资源,用HTTP描述操作. 知 ...
- Leetcode:2. 两数相加
题目描述: 给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字. 如果,我们将这两个数相加起来,则会返回一个新的链表来 ...