안녕하세요 강의 잘들었습니다! springboot+thymeleaf 로 프로젝트를 하고 있는데 url 이동할때 jwt 토큰을 헤더에 유지시키는 방법이 궁금합니다. postman에서 전역변수로 토큰을 넣고 테스트하듯이 로그인을 유지하려면 헤더에 jwt값이 있어야하는데 예를 들어 user/mypage-> user/board 이런식으로 리다이렉트를하면서 헤더를 같이 보낼 수 있나요? 그게 안된다는거 같아서 화면전환할때 로그인 유지는 어떻게 시키는지 궁금합니다. 그래서 쿠키는 계속 헤더에 유지되길래 쿠키를 써야하나 생각중입니다. 비동기 식으로 ajax요청시에는 헤더에 토큰을 담아줄수 있는데 url전환시에는 로그인을 어떻게 유지시키는지 모르겠네요 미리 감사드려요
안녕하세요 질문을 둘러보았는데 저랑 딱맞는 고민은 없는거 같아서 질문드립니다. 프론트/백서버를 나누지 않고 한 서버로 구현할 경우 JWT를 페이지 이동시 매번 어떻게 헤더로 보내줄까요?? fetch api나 ajax를 통한 api 호출시 헤더 보내는것은 문제없지만 아예 다른 매핑으로 페이지를 이동할 경우 인증이 필요한 페이지에 접근하려면 header에 bearer token이 필요한데 도대체 어떤 방법으로 구현할지 모르겠습니다. 프론트서버를 나눈경우 이게 어려운게 아닌일 같은데 리다이렉션을 헤더요청과 함께하려는 꼴이 되서 안되는거 같네요,.. 그래서 일단은 cookie에 토큰값을 넣어주고 쿠키값에서 찾아오도록하고 있습니다..... 쿠키는 헤더에 자동으로 계속 추가되니깐요.. 그냥 이렇게 해도 상관없을까요 쿠키에 토큰 자체를 넣어버려도 괜찮을지요 프론트와 백이 분리 되지 않고 spring security로 설계한 서비스의 경우 jwt인증을 매 페이지 마다 어떻게 수행할지가 고민입니다. 감사합니다.
강의 너무 감사히 잘 듣고 있습니다. 강의를 들다 궁금한게 있어서 질문을 드립니다. 개인적으로 서버를 구축할떄 JWT가 간단하고 추가적으로 Redis server를 추가할 필요가 없어서 jwt를 선호합니다. 실무에서는 세션 vs JWT중 어떤것을 많이 쓰는지와 트랜드 혹은 선호되는 이유를 알 수 있을까요?
정말 너무 잘보고있습니다!! 짧지만 정말 좋았는데요...! 질문이 3개가 있습니다. 1. 이게 반환값으로 롬복 Setter가 적용된 User를 그대로 반환하고 JsonIgnore어노테이션을 붙여줬는데, 실제 프로젝트에서는 반환하는 DTO를 따로 만들고 롬복 셋터도 빼주고 빌더애들도 접근제한을 걸어주면 되는걸까요? 2. 그리고 jwt에러관련애들을 따로 패키지안에 만들어두고 각각 다른 implement를 했는데, RuntimeException을 구현(상속)받고 RestControllerAdvice로 한꺼번에 모아서 에러리스폰스를 보내줘도 되는거죠? 3. Validation에 메세지를 적었는데, 저는 json 바디에 담겨서 나올 줄 알았는데 애플리케이션 레벨에서 WARN 으로 나오는데, 서버에러 500뜨고 아무것도 안나오더라구요.. 어노테이션 메세지로 적어봤자 직접 에러객체를 만들어서 보내주지 않는 이상 Validation의 message=""는 서버개발자쪽만 보는 게 되는건가요? + 추가로 @RequestHeader를 이용하는것도 있으면 좋을것같아요! 그리고 mockMvc로 api테스트하는것과, 인텔리J의 httpRequest 파일을 활용하는 방법도있더라구요! 포스트맨처럼 환경변수 받아서 저장하는것도있구요 강의잘봤습니다
build.gradle에 JWT 관련 라이브러리들을 추가한 후 적용하게 되면 다음과 같은 오류가 발생합니다 ㅠㅠㅠ 어떻게 해결할 수 있을까요?? 여기서 진행을 못하고 있습니다 ㅠㅠㅠㅠ build.gradle은 혹시 몰라 github에 올리신 소스코드에서 복사까지 해보았지만 똑같은 문제가 계속 발생하네요 ㅠㅠ error message : A problem occurred evaluating root project 'jwt-tutorial'. > Could not find method compile() for arguments [io.jsonwebtoken:jjwt-api:0.11.2] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler. * Try: Run with --info or --debug option to get more log output. Run with --scan to get full insights. * Exception is: org.gradle.api.GradleScriptException: A problem occurred evaluating root project 'jwt-tutorial'. at org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:93) at org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.lambda$apply$0(DefaultScriptPluginFactory.java:133) at org.gradle.configuration.ProjectScriptTarget.addConfiguration(ProjectScriptTarget.java:77) at org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.apply(DefaultScriptPluginFactory.java:136) at org.gradle.configuration.BuildOperationScriptPlugin$1.run(BuildOperationScriptPlugin.java:65) at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29) at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26) at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75) at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68) at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56) at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:71) at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45) at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:71) at org.gradle.configuration.BuildOperationScriptPlugin.lambda$apply$0(BuildOperationScriptPlugin.java:62) at org.gradle.configuration.internal.DefaultUserCodeApplicationContext.apply(DefaultUserCodeApplicationContext.java:43) at org.gradle.configuration.BuildOperationScriptPlugin.apply(BuildOperationScriptPlugin.java:62) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$applyToMutableState$0(DefaultProjectStateRegistry.java:250) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.fromMutableState(DefaultProjectStateRegistry.java:277) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.applyToMutableState(DefaultProjectStateRegistry.java:249) at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:42) at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:26) at org.gradle.configuration.project.ConfigureActionsProjectEvaluator.evaluate(ConfigureActionsProjectEvaluator.java:35) at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject.lambda$run$0(LifecycleProjectEvaluator.java:100) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$applyToMutableState$0(DefaultProjectStateRegistry.java:250) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$withProjectLock$3(DefaultProjectStateRegistry.java:310) at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:213) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withProjectLock(DefaultProjectStateRegistry.java:310) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.fromMutableState(DefaultProjectStateRegistry.java:291) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.applyToMutableState(DefaultProjectStateRegistry.java:249) at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject.run(LifecycleProjectEvaluator.java:91) at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29) at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26) at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75) at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68) at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56) at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:71) at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45) at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:71) at org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:63) at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:723) at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:150) at org.gradle.execution.TaskPathProjectEvaluator.configure(TaskPathProjectEvaluator.java:41) at org.gradle.execution.TaskPathProjectEvaluator.configureHierarchy(TaskPathProjectEvaluator.java:67) at org.gradle.configuration.DefaultProjectsPreparer.prepareProjects(DefaultProjectsPreparer.java:46) at org.gradle.configuration.BuildTreePreparingProjectsPreparer.prepareProjects(BuildTreePreparingProjectsPreparer.java:64) at org.gradle.configuration.BuildOperationFiringProjectsPreparer$ConfigureBuild.run(BuildOperationFiringProjectsPreparer.java:52) at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29) at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26) at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75) at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68) at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56) at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:71) at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45) at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:71) at org.gradle.configuration.BuildOperationFiringProjectsPreparer.prepareProjects(BuildOperationFiringProjectsPreparer.java:40) at org.gradle.initialization.DefaultGradleLauncher.prepareProjects(DefaultGradleLauncher.java:226) at org.gradle.initialization.DefaultGradleLauncher.doClassicBuildStages(DefaultGradleLauncher.java:164) at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:149) at org.gradle.initialization.DefaultGradleLauncher.executeTasks(DefaultGradleLauncher.java:125) at org.gradle.internal.invocation.GradleBuildController$1.create(GradleBuildController.java:71) at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:213) at org.gradle.internal.invocation.GradleBuildController.doBuild(GradleBuildController.java:67) at org.gradle.internal.invocation.GradleBuildController.run(GradleBuildController.java:56) at org.gradle.tooling.internal.provider.runner.AbstractClientProvidedBuildActionRunner.runClientAction(AbstractClientProvidedBuildActionRunner.java:53) at org.gradle.tooling.internal.provider.runner.ClientProvidedPhasedActionRunner.run(ClientProvidedPhasedActionRunner.java:47) at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35) at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35) at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:66) at org.gradle.tooling.internal.provider.ValidatingBuildActionRunner.run(ValidatingBuildActionRunner.java:32) at org.gradle.tooling.internal.provider.FileSystemWatchingBuildActionRunner.run(FileSystemWatchingBuildActionRunner.java:90) at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:41) at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$3.call(RunAsBuildOperationBuildActionRunner.java:49) at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$3.call(RunAsBuildOperationBuildActionRunner.java:44) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195) at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75) at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68) at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:62) at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$call$2(DefaultBuildOperationExecutor.java:76) at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.callWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:54) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:76) at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner.run(RunAsBuildOperationBuildActionRunner.java:44) at org.gradle.launcher.exec.InProcessBuildActionExecuter.lambda$execute$0(InProcessBuildActionExecuter.java:59) at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:86) at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:58) at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:30) at org.gradle.launcher.exec.BuildTreeScopeLifecycleBuildActionExecuter.lambda$execute$0(BuildTreeScopeLifecycleBuildActionExecuter.java:34) at org.gradle.internal.buildtree.BuildTreeState.run(BuildTreeState.java:53) at org.gradle.launcher.exec.BuildTreeScopeLifecycleBuildActionExecuter.execute(BuildTreeScopeLifecycleBuildActionExecuter.java:33) at org.gradle.launcher.exec.BuildTreeScopeLifecycleBuildActionExecuter.execute(BuildTreeScopeLifecycleBuildActionExecuter.java:28) at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:104) at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:55) at org.gradle.tooling.internal.provider.SubscribableBuildActionExecuter.execute(SubscribableBuildActionExecuter.java:64) at org.gradle.tooling.internal.provider.SubscribableBuildActionExecuter.execute(SubscribableBuildActionExecuter.java:37) at org.gradle.tooling.internal.provider.SessionScopeLifecycleBuildActionExecuter.lambda$execute$0(SessionScopeLifecycleBuildActionExecuter.java:54) at org.gradle.internal.session.BuildSessionState.run(BuildSessionState.java:67) at org.gradle.tooling.internal.provider.SessionScopeLifecycleBuildActionExecuter.execute(SessionScopeLifecycleBuildActionExecuter.java:50) at org.gradle.tooling.internal.provider.SessionScopeLifecycleBuildActionExecuter.execute(SessionScopeLifecycleBuildActionExecuter.java:36) at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:36) at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:25) at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:59) at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:31) at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:58) at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:42) at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:47) at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:31) at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:65) at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:29) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:78) at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:75) at org.gradle.util.Swapper.swap(Swapper.java:38) at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:75) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63) at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:84) at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52) at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48) at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56) Caused by: org.gradle.internal.metaobject.AbstractDynamicObject$CustomMessageMissingMethodException: Could not find method compile() for arguments [io.jsonwebtoken:jjwt-api:0.11.2] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler. at org.gradle.internal.metaobject.AbstractDynamicObject$CustomMissingMethodExecutionFailed.<init>(AbstractDynamicObject.java:190) at org.gradle.internal.metaobject.AbstractDynamicObject.methodMissingException(AbstractDynamicObject.java:184) at org.gradle.internal.metaobject.ConfigureDelegate.invokeMethod(ConfigureDelegate.java:86)
안녕하세요 강의 재밌게 보고 있습니다. 제가 프론트엔드에는 무지하여 잘 모르겠는데 jwt 를 서버에서 반환해주면 프론트에서는 일반적으로 어디에 저장을 하다가 요청 보낼때 마다 재사용하나요? 로컬 스토리지나 쿠키 정도 밖에 떠오르는게 없는데 프론트엔드 현업에서 자주 사용하는 방식이 있나요?
1. 제가 지금 까지 강의를 듣고 이해한 것 으로는 세션은 서버 에서 session(메모리) 형태로 로그인 정보를 저장해두고 쿠키 (브라우저에서) session ID 를 저장해 놓으면 새로고침 할 때 마다 session ID 로 session 을 조회하여 로그인 시켜주는 것 으로 알고 있는데 정확히 이것이 맞나요?? 잘 이해가 안되서 요.. ㅠㅠ 강의 도중 JWT 가 알맞는 프로젝트가 있고 session 이 알맞는 프로젝트가 있다고 하셨는데.. 제가 (초급자 입장에서) 봤을 때 는 JWT 가 무조건 이득일 것 같습니다.. session 은 redis(추 가비용 발생!) 도 있고 또 load balancer 서버도 있어야 하는 것으로 알고있는데..(자세히는 모르지만 주워들었습니다..) 코 딩도 비교적 양이 많을 것 같아요. 2. JWT가 알맞는 프로젝트와 Session 이 알맞는 프로젝트를 예시로 들어주실 수 있으신가요..? 3. JWT 가 네트워크 용량이 늘어 난 다는 것 외에 단점이 있을까요?