From 03412935121b747bcb6cb2c646f3c0783c5e006c Mon Sep 17 00:00:00 2001 From: wzp Date: Sun, 7 Apr 2024 17:58:59 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat(all):=20=E6=B7=BB=E5=8A=A0=E4=BA=86JWT?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../annotations/AuthorizationRequired.java | 10 ++++ .../configuration/TokenConfiguration.java | 53 +++++++++++++++++++ .../mmga/clubs/controller/UserController.java | 6 +++ .../org/mmga/clubs/service/UserService.java | 3 ++ .../java/org/mmga/clubs/utils/JwtUtils.java | 7 +++ 5 files changed, 79 insertions(+) create mode 100644 src/main/java/org/mmga/clubs/annotations/AuthorizationRequired.java create mode 100644 src/main/java/org/mmga/clubs/configuration/TokenConfiguration.java diff --git a/src/main/java/org/mmga/clubs/annotations/AuthorizationRequired.java b/src/main/java/org/mmga/clubs/annotations/AuthorizationRequired.java new file mode 100644 index 0000000..661f83d --- /dev/null +++ b/src/main/java/org/mmga/clubs/annotations/AuthorizationRequired.java @@ -0,0 +1,10 @@ +package org.mmga.clubs.annotations; + +import java.lang.annotation.*; + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface AuthorizationRequired { + +} diff --git a/src/main/java/org/mmga/clubs/configuration/TokenConfiguration.java b/src/main/java/org/mmga/clubs/configuration/TokenConfiguration.java new file mode 100644 index 0000000..6361dc0 --- /dev/null +++ b/src/main/java/org/mmga/clubs/configuration/TokenConfiguration.java @@ -0,0 +1,53 @@ +package org.mmga.clubs.configuration; + +import com.auth0.jwt.exceptions.JWTVerificationException; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import org.mmga.clubs.annotations.AuthorizationRequired; +import org.mmga.clubs.entities.BaseResponse; +import org.mmga.clubs.utils.JwtUtils; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.nio.charset.StandardCharsets; + +@Configuration +@Slf4j +public class TokenConfiguration implements HandlerInterceptor, WebMvcConfigurer{ + private final JwtUtils jwtUtils; + public TokenConfiguration(JwtUtils jwtUtils){ + this.jwtUtils = jwtUtils; + } + @Override + public boolean preHandle(@NonNull HttpServletRequest request,@NonNull HttpServletResponse response,@NonNull Object handler) throws Exception { + if (handler instanceof HandlerMethod handlerMethod){ + if (handlerMethod.hasMethodAnnotation(AuthorizationRequired.class)){ + String authorization = request.getHeader("Authorization"); + try{ + jwtUtils.verifyToken(authorization); + }catch (JWTVerificationException e){ + log.debug("用户鉴权时出现错误:", e); + ServletOutputStream outputStream = response.getOutputStream(); + response.addHeader("Content-Encoding", "UTF-8"); + //TODO 使用fastjson2 进行json序列化 + BaseResponse err = BaseResponse.failed(401, "token错误"); + outputStream.write(err.toString().getBytes(StandardCharsets.UTF_8)); + outputStream.close(); + return false; + } + return true; + } + } + return true; + } + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(this); + } +} diff --git a/src/main/java/org/mmga/clubs/controller/UserController.java b/src/main/java/org/mmga/clubs/controller/UserController.java index 702e41c..827edf4 100644 --- a/src/main/java/org/mmga/clubs/controller/UserController.java +++ b/src/main/java/org/mmga/clubs/controller/UserController.java @@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; +import org.mmga.clubs.annotations.AuthorizationRequired; import org.mmga.clubs.entities.BaseResponse; import org.mmga.clubs.entities.user.User; import org.mmga.clubs.entities.user.UserLoginVo; @@ -33,4 +34,9 @@ public class UserController { public BaseResponse createUser(@RequestBody UserRegVo user, HttpServletResponse response){ return service.createUser(user, response); } + @GetMapping("/test") + @AuthorizationRequired + public BaseResponse test(){ + return BaseResponse.success(true); + } } diff --git a/src/main/java/org/mmga/clubs/service/UserService.java b/src/main/java/org/mmga/clubs/service/UserService.java index c3373e4..f2d5c8c 100644 --- a/src/main/java/org/mmga/clubs/service/UserService.java +++ b/src/main/java/org/mmga/clubs/service/UserService.java @@ -44,6 +44,9 @@ public class UserService { } return BaseResponse.success(newUser); } + public User getUserById(int id){ + return packageUser(userDao.getUserById(id)); + } private User packageUser(UserVo vo) { if (vo == null){ return null; diff --git a/src/main/java/org/mmga/clubs/utils/JwtUtils.java b/src/main/java/org/mmga/clubs/utils/JwtUtils.java index b085014..8d81282 100644 --- a/src/main/java/org/mmga/clubs/utils/JwtUtils.java +++ b/src/main/java/org/mmga/clubs/utils/JwtUtils.java @@ -2,8 +2,11 @@ package org.mmga.clubs.utils; import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.JWTVerificationException; +import com.auth0.jwt.interfaces.DecodedJWT; import lombok.extern.slf4j.Slf4j; import org.mmga.clubs.entities.user.User; +import org.mmga.clubs.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -25,4 +28,8 @@ public class JwtUtils { log.debug("对用户:{},生成JWT:{}", user.getName(), jwt); return jwt; } + public Integer verifyToken(String token) throws JWTVerificationException { + DecodedJWT verify = JWT.require(Algorithm.ECDSA512(ecPublicKey, ecPrivateKey)).build().verify(token); + return verify.getClaim("uid").asInt(); + } } From b4c4833e44c352eaebdab13431a91702ccde87b7 Mon Sep 17 00:00:00 2001 From: wzp Date: Mon, 8 Apr 2024 16:53:41 +0800 Subject: [PATCH 2/3] =?UTF-8?q?perf(all):=20=E4=BF=AE=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8fastjson=E8=BF=9B=E8=A1=8Cjson=E5=BA=8F?= =?UTF-8?q?=E5=88=97=E5=8C=96=EF=BC=8C=E5=8E=BB=E9=99=A4=E4=BA=86jackson?= =?UTF-8?q?=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 8 +- .../configuration/FastJsonConfiguration.java | 73 +++++++++++++++++++ .../configuration/TokenConfiguration.java | 5 +- .../org/mmga/clubs/entities/BaseResponse.java | 6 +- .../mmga/clubs/entities/user/UserLoginVo.java | 2 +- 5 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 src/main/java/org/mmga/clubs/configuration/FastJsonConfiguration.java diff --git a/build.gradle.kts b/build.gradle.kts index d12190c..1b94cda 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -33,7 +33,9 @@ extra["springShellVersion"] = "3.2.3" dependencies { implementation("org.springframework.boot:spring-boot-starter-actuator") - implementation("org.springframework.boot:spring-boot-starter-web") + implementation("org.springframework.boot:spring-boot-starter-web") { + exclude("com.fasterxml.jackson.core", "jackson-core") + } implementation("org.springframework.boot:spring-boot-starter-websocket") implementation("org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3") implementation("org.springframework.shell:spring-shell-starter") @@ -42,6 +44,10 @@ dependencies { // https://mvnrepository.com/artifact/commons-codec/commons-codec implementation("commons-codec:commons-codec:1.16.1") // https://mvnrepository.com/artifact/com.auth0/java-jwt + // https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2 + implementation("com.alibaba.fastjson2:fastjson2:2.0.48") +// https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2-extension-spring6 + implementation("com.alibaba.fastjson2:fastjson2-extension-spring6:2.0.48") implementation("com.auth0:java-jwt:4.4.0") compileOnly("org.projectlombok:lombok") developmentOnly("org.springframework.boot:spring-boot-devtools") diff --git a/src/main/java/org/mmga/clubs/configuration/FastJsonConfiguration.java b/src/main/java/org/mmga/clubs/configuration/FastJsonConfiguration.java new file mode 100644 index 0000000..1021ea9 --- /dev/null +++ b/src/main/java/org/mmga/clubs/configuration/FastJsonConfiguration.java @@ -0,0 +1,73 @@ +package org.mmga.clubs.configuration; + +import com.alibaba.fastjson2.JSONWriter; +import com.alibaba.fastjson2.support.config.FastJsonConfig; +import com.alibaba.fastjson2.support.spring6.http.converter.FastJsonHttpMessageConverter; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +@Configuration +public class FastJsonConfiguration implements WebMvcConfigurer { + /** + * 配置fastjson输出格式 + **/ + @Override + public void configureMessageConverters(List> converters) { + // 1. 配置fastjson + FastJsonConfig config = new FastJsonConfig(); + + config.setDateFormat("yyyy-MM-dd HH:mm:ss"); + config.setCharset(StandardCharsets.UTF_8); + config.setWriterFeatures( + JSONWriter.Feature.WriteNullListAsEmpty, + //json格式化 + JSONWriter.Feature.PrettyFormat, + //输出map中value为null的数据 + JSONWriter.Feature.WriteMapNullValue, + //输出boolean 为 false + JSONWriter.Feature.WriteNullBooleanAsFalse, + //输出list 为 [] + JSONWriter.Feature.WriteNullListAsEmpty, + //输出number 为 0 + JSONWriter.Feature.WriteNullNumberAsZero, + //输出字符串 为 "" + JSONWriter.Feature.WriteNullStringAsEmpty, + //对map进行排序 + JSONWriter.Feature.SortMapEntriesByKeys + ); + + // 2. 添加fastjson转换器 + FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); + List supportedMediaTypes = new ArrayList<>(); + + // 3. 添加支持的媒体类型 + supportedMediaTypes.add(MediaType.APPLICATION_JSON); + supportedMediaTypes.add(MediaType.APPLICATION_ATOM_XML); + supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED); + supportedMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM); + supportedMediaTypes.add(MediaType.APPLICATION_PDF); + supportedMediaTypes.add(MediaType.APPLICATION_RSS_XML); + supportedMediaTypes.add(MediaType.APPLICATION_XHTML_XML); + supportedMediaTypes.add(MediaType.APPLICATION_XML); + supportedMediaTypes.add(MediaType.IMAGE_GIF); + supportedMediaTypes.add(MediaType.IMAGE_JPEG); + supportedMediaTypes.add(MediaType.IMAGE_PNG); + supportedMediaTypes.add(MediaType.TEXT_EVENT_STREAM); + supportedMediaTypes.add(MediaType.TEXT_HTML); + supportedMediaTypes.add(MediaType.TEXT_MARKDOWN); + supportedMediaTypes.add(MediaType.TEXT_PLAIN); + supportedMediaTypes.add(MediaType.TEXT_XML); + + converter.setSupportedMediaTypes(supportedMediaTypes); + + //4 将convert添加到converters + converter.setFastJsonConfig(config); + converters.add(0,converter); + } +} \ No newline at end of file diff --git a/src/main/java/org/mmga/clubs/configuration/TokenConfiguration.java b/src/main/java/org/mmga/clubs/configuration/TokenConfiguration.java index 6361dc0..7bd8471 100644 --- a/src/main/java/org/mmga/clubs/configuration/TokenConfiguration.java +++ b/src/main/java/org/mmga/clubs/configuration/TokenConfiguration.java @@ -1,5 +1,6 @@ package org.mmga.clubs.configuration; +import com.alibaba.fastjson2.JSON; import com.auth0.jwt.exceptions.JWTVerificationException; import jakarta.servlet.ServletOutputStream; import jakarta.servlet.http.HttpServletRequest; @@ -35,9 +36,9 @@ public class TokenConfiguration implements HandlerInterceptor, WebMvcConfigurer{ log.debug("用户鉴权时出现错误:", e); ServletOutputStream outputStream = response.getOutputStream(); response.addHeader("Content-Encoding", "UTF-8"); - //TODO 使用fastjson2 进行json序列化 + response.addHeader("Content-Type", "application/json; charset=utf-8"); BaseResponse err = BaseResponse.failed(401, "token错误"); - outputStream.write(err.toString().getBytes(StandardCharsets.UTF_8)); + outputStream.write(JSON.toJSONString(err).getBytes(StandardCharsets.UTF_8)); outputStream.close(); return false; } diff --git a/src/main/java/org/mmga/clubs/entities/BaseResponse.java b/src/main/java/org/mmga/clubs/entities/BaseResponse.java index 65dc0b7..f1a0d3d 100644 --- a/src/main/java/org/mmga/clubs/entities/BaseResponse.java +++ b/src/main/java/org/mmga/clubs/entities/BaseResponse.java @@ -2,7 +2,8 @@ package org.mmga.clubs.entities; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import org.mmga.clubs.entities.user.User; + +import java.util.Date; @Data @Schema(description = "基础返回值") @@ -11,12 +12,15 @@ public class BaseResponse { private int code; @Schema(description = "返回信息(自定义)") private String msg; + @Schema(description = "响应生成时间") + private final Date time; @Schema(description = "返回数据") private T data; private BaseResponse(int code, String msg, T data){ this.code = code; this.msg = msg; this.data = data; + this.time = new Date(); } public static BaseResponse success(T data){ return new BaseResponse<>(200, "接口执行成功", data); diff --git a/src/main/java/org/mmga/clubs/entities/user/UserLoginVo.java b/src/main/java/org/mmga/clubs/entities/user/UserLoginVo.java index 1174fcb..7883577 100644 --- a/src/main/java/org/mmga/clubs/entities/user/UserLoginVo.java +++ b/src/main/java/org/mmga/clubs/entities/user/UserLoginVo.java @@ -3,5 +3,5 @@ package org.mmga.clubs.entities.user; import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "用户登录参数类") -public record UserLoginVo(@Schema(description = "用户名") String username,@Schema(description = "用户密码(使用MD5摘要后的hex字符串)") String password) { +public record UserLoginVo(@Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED) String username, @Schema(description = "用户密码(使用MD5摘要后的hex字符串)") String password) { } From db36ed3fb090c94d975d116b34292c72c75f4aac Mon Sep 17 00:00:00 2001 From: wzp Date: Mon, 8 Apr 2024 17:52:43 +0800 Subject: [PATCH 3/3] =?UTF-8?q?feat(all):=20=E6=B7=BB=E5=8A=A0=E4=BA=86?= =?UTF-8?q?=E9=89=B4=E6=9D=83=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/mmga/clubs/commands/UserCommands.java | 31 ------------------- .../configuration/TokenConfiguration.java | 13 ++++---- .../mmga/clubs/controller/UserController.java | 14 ++++----- .../org/mmga/clubs/service/UserService.java | 22 ++++++++++--- 4 files changed, 32 insertions(+), 48 deletions(-) delete mode 100644 src/main/java/org/mmga/clubs/commands/UserCommands.java diff --git a/src/main/java/org/mmga/clubs/commands/UserCommands.java b/src/main/java/org/mmga/clubs/commands/UserCommands.java deleted file mode 100644 index 7105c2b..0000000 --- a/src/main/java/org/mmga/clubs/commands/UserCommands.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.mmga.clubs.commands; - -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.codec.digest.DigestUtils; -import org.mmga.clubs.controller.UserController; -import org.mmga.clubs.entities.BaseResponse; -import org.mmga.clubs.entities.user.User; -import org.mmga.clubs.entities.user.UserLoginVo; -import org.mmga.clubs.entities.user.UserRegVo; -import org.mmga.clubs.utils.ShellUtils; -import org.springframework.shell.standard.ShellComponent; -import org.springframework.shell.standard.ShellMethod; - -@ShellComponent -@Slf4j -public class UserCommands { - private final UserController userController; - public UserCommands(UserController userController){ - this.userController = userController; - } - @ShellMethod("创建用户") - public void createUser(String name, String password) { - BaseResponse user = this.userController.createUser(new UserRegVo(name, DigestUtils.md5Hex(password), 1), null); - ShellUtils.logToResult(log, user); - } - @ShellMethod("登录") - public void login(String name, String password) { - BaseResponse user = this.userController.login(new UserLoginVo(name, DigestUtils.md5Hex(password)), null); - ShellUtils.logToResult(log, user); - } -} diff --git a/src/main/java/org/mmga/clubs/configuration/TokenConfiguration.java b/src/main/java/org/mmga/clubs/configuration/TokenConfiguration.java index 7bd8471..30d5287 100644 --- a/src/main/java/org/mmga/clubs/configuration/TokenConfiguration.java +++ b/src/main/java/org/mmga/clubs/configuration/TokenConfiguration.java @@ -28,11 +28,13 @@ public class TokenConfiguration implements HandlerInterceptor, WebMvcConfigurer{ @Override public boolean preHandle(@NonNull HttpServletRequest request,@NonNull HttpServletResponse response,@NonNull Object handler) throws Exception { if (handler instanceof HandlerMethod handlerMethod){ - if (handlerMethod.hasMethodAnnotation(AuthorizationRequired.class)){ - String authorization = request.getHeader("Authorization"); - try{ - jwtUtils.verifyToken(authorization); - }catch (JWTVerificationException e){ + request.setAttribute("user", -1); + String authorization = request.getHeader("Authorization"); + try{ + Integer userId = jwtUtils.verifyToken(authorization); + request.setAttribute("user", userId); + }catch (JWTVerificationException e){ + if (handlerMethod.hasMethodAnnotation(AuthorizationRequired.class)) { log.debug("用户鉴权时出现错误:", e); ServletOutputStream outputStream = response.getOutputStream(); response.addHeader("Content-Encoding", "UTF-8"); @@ -42,7 +44,6 @@ public class TokenConfiguration implements HandlerInterceptor, WebMvcConfigurer{ outputStream.close(); return false; } - return true; } } return true; diff --git a/src/main/java/org/mmga/clubs/controller/UserController.java b/src/main/java/org/mmga/clubs/controller/UserController.java index 827edf4..45ed9dd 100644 --- a/src/main/java/org/mmga/clubs/controller/UserController.java +++ b/src/main/java/org/mmga/clubs/controller/UserController.java @@ -5,7 +5,6 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; -import org.mmga.clubs.annotations.AuthorizationRequired; import org.mmga.clubs.entities.BaseResponse; import org.mmga.clubs.entities.user.User; import org.mmga.clubs.entities.user.UserLoginVo; @@ -18,6 +17,7 @@ import org.springframework.web.bind.annotation.*; @RequestMapping("/api/user") @Tag(name = "用户", description = "用户相关接口") @Slf4j +@CrossOrigin(allowCredentials = "true", allowedHeaders = {"Set-Authorization", "Authorization"}, origins = {"http://localhost:5173"}) public class UserController { private final UserService service; @Autowired @@ -26,17 +26,17 @@ public class UserController { } @PostMapping("/login") @Operation(description = "用户登录", responses = {@ApiResponse(description = "返回是否登录成功", responseCode = "200")}) - public BaseResponse login(@RequestBody UserLoginVo user, HttpServletResponse response){ + public BaseResponse login(@RequestBody UserLoginVo user, HttpServletResponse response){ return service.login(user, response); } @PutMapping("/create") @Operation(description = "创建用户", responses = {@ApiResponse(description = "返回创建后的用户")}) - public BaseResponse createUser(@RequestBody UserRegVo user, HttpServletResponse response){ + public BaseResponse createUser(@RequestBody UserRegVo user, HttpServletResponse response){ return service.createUser(user, response); } - @GetMapping("/test") - @AuthorizationRequired - public BaseResponse test(){ - return BaseResponse.success(true); + @GetMapping("/info") + @Operation(description = "获取用户信息") + public BaseResponse getUserInfo(@RequestAttribute("user") int userId){ + return service.getUserInfo(userId); } } diff --git a/src/main/java/org/mmga/clubs/service/UserService.java b/src/main/java/org/mmga/clubs/service/UserService.java index f2d5c8c..82cda06 100644 --- a/src/main/java/org/mmga/clubs/service/UserService.java +++ b/src/main/java/org/mmga/clubs/service/UserService.java @@ -21,16 +21,16 @@ public class UserService { this.jwtUtils = jwtUtils; } - public BaseResponse login(UserLoginVo user, HttpServletResponse response) { + public BaseResponse login(UserLoginVo user, HttpServletResponse response) { UserVo userVo = userDao.getUser(user.username(), DigestUtils.sha1Hex(user.password())); User u = packageUser(userVo); if (response != null && u != null){ response.addHeader("Set-Authorization", jwtUtils.createToken(u)); } - return u == null ? BaseResponse.failed(404, "无效用户") : BaseResponse.success(u); + return u == null ? BaseResponse.failed(404, "无效用户") : BaseResponse.success(true); } - public BaseResponse createUser(UserRegVo user, HttpServletResponse response) { + public BaseResponse createUser(UserRegVo user, HttpServletResponse response) { String username = user.username(); if (userDao.countUser(username) > 0) { return BaseResponse.failed(409, "用户已存在"); @@ -42,11 +42,18 @@ public class UserService { if (newUser != null && response != null) { response.addHeader("Set-Authorization", jwtUtils.createToken(newUser)); } - return BaseResponse.success(newUser); + return BaseResponse.success(true); } public User getUserById(int id){ return packageUser(userDao.getUserById(id)); } + public User getGuestUser(){ + User user = new User(); + user.setId(-1); + user.setName("游客"); + user.setAuth(authService.getAuthById(1)); + return user; + } private User packageUser(UserVo vo) { if (vo == null){ return null; @@ -57,4 +64,11 @@ public class UserService { result.setAuth(authService.getAuthById(vo.auth())); return result; } + + public BaseResponse getUserInfo(int userId) { + if (userId == -1){ + return BaseResponse.success(getGuestUser()); + } + return BaseResponse.success(getUserById(userId)); + } }