SpringBoot OAuth2场景下获取clientId实现用户客户端权限校验咨询
问题根因
你当前的obtainClientId方法仅解析Authorization请求头里的Basic认证信息,而用户提交用户名密码的登录请求是浏览器发起的表单请求,不会携带客户端的Basic认证头,所以返回为空。
解决方案
方案1:登录表单隐藏域传递client_id(最推荐)
OAuth2授权端点/authorize收到客户端的授权请求时必然携带client_id参数,你可以在跳转登录页时将该参数透传给前端,放在登录表单的隐藏域中,用户提交登录时会自动携带该参数,直接从请求参数中读取即可。
实现步骤:
- 自定义认证入口点,跳转登录页时将请求中的
client_id拼到登录页URL参数中 - 登录页模板添加隐藏表单字段:
<input type="hidden" name="client_id" value="${param.client_id}"> - 修改
obtainClientId方法,优先读取请求参数:
private String obtainClientId(HttpServletRequest request){ // 优先读取表单提交的client_id String clientId = request.getParameter("client_id"); if (StringUtils.hasText(clientId)) { return clientId; } // 兼容客户端凭证等不需要表单登录的场景 final String authorizationHeaderValue = request.getHeader("Authorization"); final String base64AuthorizationHeader = Optional.ofNullable(authorizationHeaderValue) .map(headerValue->headerValue.substring("Basic ".length())).orElse(""); if(!StringUtils.isEmpty(base64AuthorizationHeader)){ String decodedAuthorizationHeader = new String(Base64.getDecoder().decode(base64AuthorizationHeader), Charset.forName("UTF-8")); return decodedAuthorizationHeader.split(":")[0]; } return ""; }
方案2:Session存储client_id
不需要修改前端页面,在处理/authorize请求时将client_id存入当前用户的Session中,登录请求处理时直接从Session读取即可,集群部署需要提前做好Session共享配置。
实现步骤:
- 新增拦截器或在授权端点前置处理逻辑中添加如下代码:
String clientId = request.getParameter("client_id"); if (StringUtils.hasText(clientId)) { request.getSession().setAttribute("OAUTH2_CLIENT_ID", clientId); }
- 修改
obtainClientId方法,读取Session存储的值:
private String obtainClientId(HttpServletRequest request){ // 优先读取Session存储的client_id String clientId = (String) request.getSession().getAttribute("OAUTH2_CLIENT_ID"); if (StringUtils.hasText(clientId)) { return clientId; } // 原有逻辑保持不变 final String authorizationHeaderValue = request.getHeader("Authorization"); final String base64AuthorizationHeader = Optional.ofNullable(authorizationHeaderValue) .map(headerValue->headerValue.substring("Basic ".length())).orElse(""); if(!StringUtils.isEmpty(base64AuthorizationHeader)){ String decodedAuthorizationHeader = new String(Base64.getDecoder().decode(base64AuthorizationHeader), Charset.forName("UTF-8")); return decodedAuthorizationHeader.split(":")[0]; } return ""; }
额外优化建议
拿到client_id后不建议直接拼接用户名和client_id作为认证主体,推荐在UserDetailsService或自定义认证Provider中添加用户-客户端关联校验逻辑,若用户未绑定当前客户端直接抛出BadCredentialsException或自定义异常即可,结构更清晰也方便后续扩展。
内容的提问来源于stack exchange,提问作者JavaMan
相关产品推荐
相关产品推荐

