Spring Security Oauth2 认证(获取token/刷新token)流程(password模式)

https://blog.youkuaiyun.com/bluuusea/article/details/80284458

1.本文介绍的认证流程范围

本文主要对从用户发起获取token的请求(/oauth/token),到请求结束返回token中间经过的几个关键点进行说明。

2.认证会用到的相关请求

注:所有请求均为post请求。

  • 获取access_token请求(/oauth/token)
    请求所需参数:client_id、client_secret、grant_type、username、password
http://localhost/oauth/token?client_id=demoClientId&client_secret=demoClientSecret&grant_type=password&username=demoUser&password=50575tyL86xp29O380t1
 
 
 
  • 检查头肯是否有效请求(/oauth/check_token)
    请求所需参数:token
http://localhost/oauth/check_token?token=f57ce129-2d4d-4bd7-1111-f31ccc69d4d1
 
 
 
  • 刷新token请求(/oauth/token)
    请求所需参数:grant_type、refresh_token、client_id、client_secret
    其中grant_type为固定值:grant_type=refresh_token
http://localhost/oauth/token?grant_type=refresh_token&refresh_token=fbde81ee-f419-42b1-1234-9191f1f95be9&client_id=demoClientId&client_secret=demoClientSecret
 
 
 

2.认证核心流程

注:文中介绍的认证服务器端token存储在Reids,用户信息存储使用数据库,文中会包含相关的部分代码。

2.1.获取token的主要流程:

加粗内容为每一步的重点,不想细看的可以只看加粗内容:

  1. 用户发起获取token的请求。
  2. 过滤器会验证path是否是认证的请求/oauth/token,如果为false,则直接返回没有后续操作。
  3. 过滤器通过clientId查询生成一个Authentication对象
  4. 然后会通过username和生成的Authentication对象生成一个UserDetails对象,并检查用户是否存在。
  5. 以上全部通过会进入地址/oauth/token,即TokenEndpoint的postAccessToken方法中。
  6. postAccessToken方法中会验证Scope,然后验证是否是refreshToken请求等。
  7. 之后调用AbstractTokenGranter中的grant方法。
  8. grant方法中调用AbstractUserDetailsAuthenticationProvider的authenticate方法,通过username和Authentication对象来检索用户是否存在
  9. 然后通过DefaultTokenServices类从tokenStore中获取OAuth2AccessToken对象
  10. 然后将OAuth2AccessToken对象包装进响应流返回

2.2.刷新token(refresh token)的流程

刷新token(refresh token)的流程与获取token的流程只有⑨有所区别:

  • 获取token调用的是AbstractTokenGranter中的getAccessToken方法,然后调用tokenStore中的getAccessToken方法获取token。
  • 刷新token调用的是RefreshTokenGranter中的getAccessToken方法,然后使用tokenStore中的refreshAccessToken方法获取token。

2.3.tokenStore的特点

tokenStore通常情况为自定义实现,一般放置在缓存或者数据库中。此处可以利用自定义tokenStore来实现多种需求,如:

  • 同已用户每次获取token,获取到的都是同一个token,只有token失效后才会获取新token。
  • 同一用户每次获取token都生成一个完成周期的token并且保证每次生成的token都能够使用(多点登录)。
  • 同一用户每次获取token都保证只有最后一个token能够使用,之前的token都设为无效(单点token)。

3.获取token的详细流程(代码截图)

3.1.代码截图梳理流程

1.一个比较重要的过滤器
这里写图片描述
2.此处是①中的attemptAuthentication方法

Spring Security OAuth2 中,内部服务调用 `/oauth/token` 接口获取令牌时,需要确保请求的格式、认证方式以及权限配置均符合 OAuth2 协议的要求。以下是实现该功能的关键步骤和注意事项。 ### 3.1 请求格式与参数设置 调用 `/oauth/token` 接口时,必须使用 `application/x-www-form-urlencoded` 格式,并传递必要的参数,包括 `grant_type`、`client_id` 和 `client_secret`。如果是密码模式,还需要提供 `username` 和 `password`。例如: ```java Map<String, String> params = new HashMap<>(); params.put("grant_type", "password"); params.put("client_id", "your_client_id"); params.put("client_secret", "your_client_secret"); params.put("username", "user"); params.put("password", "password"); ``` 请求头中应设置 `Content-Type: application/x-www-form-urlencoded`,以确保服务端能正确解析参数[^2]。 ### 3.2 安全配置放行 `/oauth/token` 接口 默认情况下,Spring Security 会对 `/oauth/token` 接口进行安全限制。为了允许内部服务调用该接口,需在 `HttpSecurity` 配置中放行该路径: ```java @Override public void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/oauth/token").permitAll() .anyRequest().authenticated() .and() .httpBasic() .and() .csrf().disable(); } ``` 此配置确保 `/oauth/token` 接口无需认证即可访问,同时其他接口仍受保护[^1]。 ### 3.3 使用 RestTemplate 发起请求 在 Spring 应用中,通常使用 `RestTemplate` 或 `WebClient` 发起 HTTP 请求。以下是一个使用 `RestTemplate` 的示例: ```java @Autowired private RestTemplate restTemplate; public String getAccessToken() { String tokenUrl = "http://auth-server/oauth/token"; HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); headers.setBasicAuth("your_client_id", "your_client_secret"); HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers); ResponseEntity<String> response = restTemplate.postForEntity(tokenUrl, request, String.class); return response.getBody(); } ``` 该请求使用 `Basic Auth` 对客户端进行认证,并以 `application/x-www-form-urlencoded` 格式提交参数[^2]。 ### 3.4 自定义 Token 服务配置 确保 `DefaultTokenServices` 正确配置了 `TokenStore` 和 `ClientDetailsService`,以支持令牌的生成与验证: ```java @Bean public DefaultTokenServices tokenServices(TokenStore tokenStore, ClientDetailsService clientDetailsService) { DefaultTokenServices tokenServices = new DefaultTokenServices(); tokenServices.setTokenStore(tokenStore); tokenServices.setClientDetailsService(clientDetailsService); tokenServices.setSupportRefreshToken(true); return tokenServices; } ``` 如果 `TokenStore` 或 `ClientDetailsService` 未正确配置,可能导致 Token 生成失败或无法验证客户端信息[^4]。 ### 3.5 处理 401 认证错误 在调用 `/oauth/token` 接口时,如果返回 `401 authentication is required` 错误,通常是因为客户端认证失败。确保客户端信息(`client_id` 和 `client_secret`)正确,并且在数据库中已注册。此外,检查 `ClientDetailsService` 的实现是否正确加载客户端信息[^3]。 ###
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hello_world!

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值