Vert.x 4.2.5中Mongo身份认证提供者认证成功后未在路由上下文注入User对象问题
问题分析与解决方案
你的问题核心在于登录成功后没有将认证用户绑定到会话,且私有路由的认证逻辑没有适配会话登录的场景,导致后续请求无法识别已登录用户,也拿不到RoutingContext中的User对象。我帮你一步步修正:
1. 核心问题拆解
- 你的
login方法仅完成了用户认证,但没有把认证后的User对象存入会话,导致后续请求无法通过会话识别用户; - 私有路由只配置了
BasicAuthHandler,它只会验证请求头中的Basic Auth凭证,而你登录后是通过会话保持状态的,不会每次请求都带Basic Auth头,所以Handler会拦截未携带凭证的请求。
2. 代码修改方案
第一步:完善登录逻辑,将用户绑定到会话
修改login方法,认证成功后必须把User对象设置到RoutingContext中,SessionHandler会自动将用户信息序列化到会话里:
private void login(RoutingContext routingContext) { JsonObject body = routingContext.getBodyAsJson(); JsonObject authInfo = new JsonObject() .put("username", body.getString("username")) .put("password", body.getString("password")); authenticationProvider.authenticate(authInfo).onSuccess(user -> { // 关键:将认证用户绑定到上下文,SessionHandler会自动同步到会话 routingContext.setUser(user); routingContext.response() .setStatusCode(200) .putHeader("Content-Type", "application/json") .end(new JsonObject().put("success", true).encode()); }).onFailure(err -> { // 别忘了处理认证失败的情况 routingContext.response() .setStatusCode(401) .putHeader("Content-Type", "application/json") .end(new JsonObject().put("success", false).put("error", err.getMessage()).encode()); }); }
第二步:调整私有路由的认证逻辑,支持会话登录
使用SessionAuthHandler替代(或配合)BasicAuthHandler,它会优先从会话中查找已认证的用户,这样登录后的请求无需再携带Basic Auth头:
Router apiAuth = Router.router(vertx); SessionStore store = LocalSessionStore.create(vertx); SessionHandler sessionHandler = SessionHandler.create(store); apiAuth.route().handler(sessionHandler); apiAuth.route().handler(BodyHandler.create()); AuthenticationHandler basicAuthHandler = BasicAuthHandler.create(authenticationProvider); // 新增SessionAuthHandler,从会话中读取已登录用户 AuthenticationHandler sessionAuthHandler = SessionAuthHandler.create(authenticationProvider); apiAuth.post("/login").handler(this::login); // 私有路由先检查会话中的用户,没有的话再要求Basic认证(可选) apiAuth.get("/checkLogin").handler(sessionAuthHandler); apiAuth.get("/checkLogin").handler(basicAuthHandler); // 如果需要同时支持两种认证方式可以保留 apiAuth.get("/checkLogin").handler(this::checkLogin);
第三步:在私有路由中获取User对象
修改checkLogin方法,通过routingContext.user()获取已绑定的用户对象:
private void checkLogin(RoutingContext routingContext) { User user = routingContext.user(); JsonObject response = new JsonObject(); if (user != null) { response.put("authenticated", true) .put("username", user.principal().getString("username")); routingContext.response().setStatusCode(200).end(response.encode()); } else { response.put("authenticated", false); routingContext.response().setStatusCode(401).end(response.encode()); } }
3. 额外注意事项
- 确保你的MongoDB认证提供者配置正确,返回的
User对象包含有效的principal信息(比如用户名、用户ID); - 测试时要确保请求携带会话Cookie(Vert.x的SessionHandler默认会设置
vertx-web.sessionCookie),否则会话无法被识别; - 如果不需要同时支持Basic Auth和会话登录,可以只保留
SessionAuthHandler在私有路由上。
内容的提问来源于stack exchange,提问作者Ilyass Asri
相关产品推荐
相关产品推荐

