我试图将SAML实现到我的应用程序中,该应用程序由SPA (Flutter Web)和REST API (Springboot)组成。但是在实现Flutter前端应用程序、Springboot Rest API和SAML身份提供程序之间的通信时,我遇到了一个问题。
目前,我已经实现了一个初始HTTP请求(@GetMapping("/initial")),它在启动Flutter应用程序时被调用,它检查是否配置了SAML,然后将身份验证Post请求发送给身份提供者。我的问题是,身份提供者回答Rest API到另一个Post映射在RestController (@PostMapping("samlsso")。然后,我为经过身份验证的用户生成一个承载令牌,传递给Flutter应用程序来处理应用程序中的身份验证状态,并自动将用户登录。
但是我如何将这个令牌获取到Flutter应用程序?由于我使用的是REST控制器,所以我不应该在控制器中保存任何变量,但是为了让Flutter应用程序从REST API接收数据,它必须为令牌本身发送请求。但是Flutter应用程序不知道何时可以接收令牌。我怎样才能正确地实现这种通信,而不需要任何手动延迟和在RestController类中的变量中保存值?
PS:我已经尝试发送一个响应。从接收和处理SAML响应的PostMapping直接重定向到Frontend,但我只能通过header发送它,并且无法从Flutter应用程序访问它。
后端代码:
@RestController
class SamlController {
var samlToken = ""
@GetMapping("/initial")
fun findToken() {
sendAuthRequestToIdp()
}
@PostMapping("/samlsso")
fun findAll(request: HttpServletRequest, response: HttpServletResponse) {
val user = receiveAndHandleIDPResponse()
//handle errors
val token = generateTokenFromIDPResponse()
samlToken = token
}
@PostMapping("/getSamlToken")
fun findAll(): ResponseEntity<String> {
return ResponseEntity.ok(samlToken)
}
}
前端代码:
Future<String> fetchSamlAuthentication () async {
var jwtString = '';
await launch("api_url/initial"); // launch, so that the IDP website opens in the browser
await Future.delayed(const Duration(milliseconds: 10000));//wait manually until token has been generated
final response = await _client.post(Uri.parse("api_url/getSamlToken"), headers: headers);
jwtString = response.body;
return jwtString;
}
这是我能够使用SAML验证用户的唯一方法,但它不是一个干净/可用的解决方案。我需要一种更好的方法来获得生成的令牌到Flutter应用程序,并能够处理它。
SAML 2.0是基于浏览器的;在IdP对用户进行身份验证后,IdP通过浏览器向应用程序的后端发送一个SAML响应。这可能是您问题中对POST /samlsso
的调用。
应用程序的后端应该验证SAML响应,例如检查SAML响应中包含的任何签名是否有效,给定IdP的SAML元数据,该元数据将在SAML连接建立时预先获得。
一旦验证,应用程序的后端应该通过发送一个重定向响应来完成POST /samlsso
,该响应包含一个令牌或cookie,表明用户已经被验证。如何做到这一点取决于你的前端,特别是是否基于浏览器。
在您的情况下,由于您的应用程序的前端在浏览器中运行,并且您希望对后续请求使用承载令牌(而不是会话cookie),那么您可以将令牌包含在您重定向到的URL中,该URL应该是您的Flutter应用程序中的路由。
当你的Flutter应用重新加载时,它可以从URL中检索令牌,并通过每个请求的授权头将其传递给后续的API调用。希望您的承载令牌在创建时已被后端签名,以便后端可以在处理后续请求时验证它是否合法获得。