是否可以在 Spring Security 中仅使用刷新令牌请求访问令牌 oauth2?没有基本身份验证?
Posted
技术标签:
【中文标题】是否可以在 Spring Security 中仅使用刷新令牌请求访问令牌 oauth2?没有基本身份验证?【英文标题】:Is possible ask for an acces token oauth2 just with refresh token in spring security? without basic authentication? 【发布时间】:2020-11-07 07:55:34 【问题描述】:我想知道在春季 oauth2 中是否有可能仅使用另一个刷新令牌获得一对新的令牌(访问令牌和刷新令牌),而无需基本身份验证(没有 clientId 和 clientSecret,有什么办法吗?
例如:
具有基本身份验证
curl -u clientId:clientSecret -X POST 'http://myapplication.oauth2/accounts/oauth/token?grant_type=refresh_token&client_id=
没有基本身份验证
curl -u -X POST 'http://myapplication.oauth2/accounts/oauth/token?grant_type=refresh_token&client_id=
我注意到 spring 中的 sprint BasicAuthenticationFilter 使用下面的验证,可能会覆盖此过滤器并仅使用刷新令牌进行身份验证。
String header = request.getHeader("Authorization");
if (header == null || !header.toLowerCase().startsWith("basic "))
chain.doFilter(request, response);
return;
【问题讨论】:
我对如何解决这个问题非常感兴趣。 @georgecro 为什么要在没有客户端身份验证(没有客户端 ID 和客户端密码)的情况下刷新访问令牌?在这种情况下,OAuth 2.0 规范需要客户端身份验证。 我已经用解决方法更新了我的答案 【参考方案1】:简短的回答是否定的。用于管理 Spring Oauth 2 端点的类如下:
@FrameworkEndpoint
public class TokenEndpoint extends AbstractEndpoint
我的意思是,两个请求都获得access token
和refresh
一个使用具有不同参数的相同端点。管理这些的方法是:
@RequestMapping(
value = "/oauth/token",
method = RequestMethod.POST
)
public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException
if (!(principal instanceof Authentication))
throw new InsufficientAuthenticationException("There is no client authentication. Try adding an appropriate authentication filter.");
else
String clientId = this.getClientId(principal);
...
如您所见,Principal
对象是必需的(在本例中由基本身份验证提供)。
即使,如果您将项目的安全性配置为允许该 url 而不检查身份验证,您将在上述方法中实现“输入”,但您将收到一个 InsufficientAuthenticationException
,因为没有提供 Authentication
实例。
为什么自定义身份验证不起作用
1. 创建自定义AuthenticationProvider
将不起作用,因为之前调用了方法postAccessToken
。所以你会收到一个InsufficientAuthenticationException
。
2. 创建一个OncePerRequestFilter
并将其配置为在处理当前请求之前执行:
@Override
protected void configure(HttpSecurity http) throws Exception
http...
.anyRequest().authenticated()
.and()
.addFilterBefore(myCustomFilter, UsernamePasswordAuthenticationFilter.class);
@Override
public void configure(WebSecurity web) throws Exception
web.ignoring()
.antMatchers(POST, "/accounts/oauth/**");
带有“类似”的代码:
@Component
public class CustomAuthenticationFilter extends OncePerRequestFilter
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException
...
SecurityContextHolder.getContext().setAuthentication(
new UsernamePasswordAuthenticationToken("existingUser",
"passwordOfExistingUser",
Collections.emptyList()));
...
filterChain.doFilter(request, response);
这种方法的问题是TokenEndpoint
中的主体来自HttpServletRequest
而不是来自 Spring 上下文,正如您可以看到调试 BasicAuthenticationFilter
类。
在您的自定义过滤器中,您可以尝试使用反射在 userPrincipal
属性中设置一个值,但正如您可以验证的那样,request
有几个“内部 request
属性”,这可能是一个“太棘手的选项” ”。
总之,Oauth 标准需要用户/通行证来访问资源,如果您想在几乎所有提供的端点中解决问题,那么该项目可能不是您想要的。
在 Spring Principal 中包含您自己的对象的解决方法
我不建议这样做,但如果您仍想继续使用这种方法,有一种方法可以将您自己的值包含在 TokenEndpoint
类接收的 principal
参数中。
重要的是要考虑到 BasicAuthorizationFilter
仍将被执行,但是您可以自己覆盖 Spring 主体对象。
为此,我们可以重用以前的CustomAuthenticationFilter
,但现在您必须包含您需要的过滤器,我的意思是,允许的 url、参数等您将“打开大门”,所以要小心你的允许和不允许。
在这种情况下的不同之处在于,我们将在扩展 WebSecurityConfigurerAdapter
的类中添加配置,而不是添加:
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter
@Autowired
private CustomAuthenticationFilter customAuthenticationFilter;
...
@Override
public void configure(AuthorizationServerSecurityConfigurer security)
security.checkTokenAccess("isAuthenticated()");
security.addTokenEndpointAuthenticationFilter(customAuthenticationFilter);
...
【讨论】:
我有个想法:我看到可以设置http.csrf().disable().authenticationProvider(.....)
如果我实现自定义Authentication实例呢?
同样在这种情况下,您是如何设法实现此刷新令牌功能的?
我已经用更多信息更新了我的答案。 how did you managed...
因为在我的情况下,该微服务不是直接从“前端应用程序”调用的,我通过“后端 - 后端通信”来管理它。另一方面,如果您需要发送“应用程序用户/通行证”(我说的是“应用程序凭据”,而不是应用程序用户的特定凭据),您需要以同样的方式发送这些来自“前端应用程序”的请求,当需要获取访问令牌或刷新时,您需要在请求中继续发送这些数据。
好的,那么这个想法怎么样。我可以存储用户并将 access_token 和 refresh_token 一起传递到 Angular SPA 中。是不是太冒险了?我会检查是否可以加密它们。
Is it too risky?
是的,这是个坏主意,因为 JWT 令牌(实际上是 JWS 令牌)的有效负载是您包含在其上的信息的“base64 值”(更多信息见jwt.io)以上是关于是否可以在 Spring Security 中仅使用刷新令牌请求访问令牌 oauth2?没有基本身份验证?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 uwp 应用程序中仅使部分 gridview 项目可点击?
Spring Security 中仅使用自定义 UserDetailsService 禁止 403 [重复]
如何允许用户在 Spring Boot / Spring Security 中仅访问自己的数据?