Skip to content

Commit 6086c44

Browse files
authored
feat(fe/user): 로그인 & 회원가입 페이지 구성 변경 완료
feat(fe/user): 로그인 & 회원가입 페이지 구성 변경 완료
2 parents 23ce47a + 4362f1d commit 6086c44

File tree

13 files changed

+617
-91
lines changed

13 files changed

+617
-91
lines changed

backend/src/main/java/com/backend/domain/user/controller/AuthController.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package com.backend.domain.user.controller;
22

3+
import com.backend.domain.user.dto.LoginResponse;
4+
import com.backend.domain.user.dto.UserDto;
35
import com.backend.domain.user.service.EmailService;
46
import com.backend.domain.user.service.JwtService;
57
import com.backend.domain.user.util.JwtUtil;
8+
import com.backend.domain.user.service.UserService;
69
import com.backend.global.exception.ErrorCode;
710
import com.backend.global.response.ApiResponse;
11+
import com.backend.global.response.ResponseCode;
812
import jakarta.mail.MessagingException;
913
import jakarta.servlet.http.Cookie;
1014
import jakarta.servlet.http.HttpServletRequest;
@@ -23,6 +27,7 @@
2327
public class AuthController {
2428
private final EmailService emailService;
2529
private final JwtService jwtService;
30+
private final UserService userService;
2631
private final JwtUtil jwtUtil;
2732

2833
@Value("${jwt.access-token-expiration-in-milliseconds}")
@@ -89,11 +94,15 @@ record LoginRequest(
8994

9095

9196
@PostMapping("/api/login")
92-
public ApiResponse<String> login(
93-
@Valid @RequestBody LoginRequest loginRequest,
97+
public ApiResponse<LoginResponse> login(
98+
@RequestBody LoginRequest loginRequest,
9499
HttpServletResponse response
95100
){
96101
String token = jwtService.login(loginRequest.email, loginRequest.password);
102+
if (token == null) {
103+
// ★ 에러 분기도 LoginResponse로 타입을 고정해서 반환
104+
return ApiResponse.<LoginResponse>error(ResponseCode.UNAUTHORIZED);
105+
}
97106

98107
if(token != null) {
99108
Cookie cookie = new Cookie("token", token);
@@ -103,9 +112,11 @@ public ApiResponse<String> login(
103112

104113
cookie.setMaxAge(tokenValidityMilliSeconds);
105114

106-
response.addCookie(cookie); //응답에 쿠키 추가
115+
response.addCookie(cookie); //응답에 쿠키 추가
116+
var user = userService.findByEmail(loginRequest.email);
117+
107118

108-
return ApiResponse.success("success");
119+
return ApiResponse.success(new LoginResponse(new UserDto(user)));
109120
}else{
110121
return ApiResponse.error(ErrorCode.Login_Failed);
111122
}
@@ -144,6 +155,7 @@ public ApiResponse<String> logout(
144155
return ApiResponse.success("success");
145156
}
146157

158+
147159
public String getJwtToken(HttpServletRequest request){
148160
Cookie[] cookies = request.getCookies(); //
149161
if(cookies != null) {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.backend.domain.user.dto;
2+
3+
import com.backend.domain.user.dto.UserDto;
4+
5+
public record LoginResponse(UserDto user) {}

backend/src/main/java/com/backend/global/config/WebConfig.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ public void addCorsMappings(CorsRegistry registry) {
1515
registry.addMapping("/**")
1616
.allowedOrigins("http://localhost:3000")
1717
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH")
18-
.allowCredentials(true);
18+
.allowCredentials(false) // ← true에서 false로 변경
19+
.allowedHeaders("*") // ← 추가
20+
.exposedHeaders("Authorization"); // ← 추가
1921
}
2022
};
2123
}
22-
}
24+
}

backend/src/main/java/com/backend/global/response/ApiResponse.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ public static <T> ApiResponse<T> error(ResponseCode code) {
2424
return new ApiResponse<>(code.getCode(), code.getMessage(), null);
2525
}
2626

27+
public static <T> ApiResponse<T> error(ResponseCode code, String message) {
28+
return new ApiResponse<>(code.getCode(), message, null);
29+
}
30+
2731
public static <T> ApiResponse<T> error(ErrorCode code) {
2832
return new ApiResponse<>(code.getCode(), code.getMessage(), null);
2933
}

front/src/app/(auth)/login/page.tsx

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,42 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
1010
import { Label } from '@/components/ui/label';
1111
import { Input } from '@/components/ui/input';
1212
import { Button } from '@/components/ui/Button';
13+
import Link from 'next/link';
14+
import { Github } from 'lucide-react';
1315

1416
export default function LoginPage() {
1517
const toast = useToast();
1618
const auth = useAuth();
1719
const router = useRouter();
18-
const [username, setUsername] = useState('');
20+
const [email, setEmail] = useState('');
1921
const [password, setPassword] = useState('');
2022
const [loading, setLoading] = useState(false);
2123

2224
async function submit(e: FormEvent) {
2325
e.preventDefault();
24-
const payload: LoginRequest = { username, password };
26+
const payload: LoginRequest = { email, password };
2527
try {
2628
setLoading(true);
2729
const res = await authApi.login(payload);
28-
if (res.accessToken) {
29-
auth.loginWithToken(res.accessToken);
30-
}
31-
toast.push(res.message ?? '로그인 성공');
32-
router.push('/');
30+
31+
// 로그인 응답에서 사용자 정보 저장
32+
auth.loginWithToken(res.user);
33+
34+
toast.push('로그인 성공');
35+
36+
// 페이지 리로드하여 상태 즉시 반영
37+
window.location.href = '/';
3338
} catch (e: any) {
3439
toast.push(`로그인 실패: ${e.message}`);
3540
} finally {
3641
setLoading(false);
3742
}
3843
}
3944

45+
const handleGithubLogin = () => {
46+
alert("아직 개발중!");
47+
};
48+
4049
return (
4150
<div className="min-h-screen bg-background">
4251
<div className="container mx-auto px-4 sm:px-6 lg:px-8 py-16">
@@ -48,8 +57,8 @@ export default function LoginPage() {
4857
<CardContent>
4958
<form className="space-y-6" onSubmit={submit}>
5059
<div className="space-y-2">
51-
<Label htmlFor="username">아이디</Label>
52-
<Input id="username" value={username} onChange={(e) => setUsername(e.target.value)} required />
60+
<Label htmlFor="email">이메일</Label>
61+
<Input id="email" type="email" value={email} onChange={(e) => setEmail(e.target.value)} required />
5362
</div>
5463
<div className="space-y-2">
5564
<Label htmlFor="password">비밀번호</Label>
@@ -58,7 +67,22 @@ export default function LoginPage() {
5867
<Button type="submit" className="w-full" size="lg" disabled={loading}>
5968
{loading ? '처리중...' : '로그인'}
6069
</Button>
61-
<p className="text-xs text-muted-foreground">스프링 엔드포인트: POST /api/v1/auth/login</p>
70+
<Button
71+
type="button"
72+
variant="outline"
73+
className="w-full"
74+
size="lg"
75+
onClick={handleGithubLogin}
76+
>
77+
<Github className="mr-2 h-4 w-4" />
78+
Github으로 로그인하기
79+
</Button>
80+
<div className="text-center">
81+
<span className="text-sm text-muted-foreground">처음이신가요? </span>
82+
<Link href="/signup" className="text-sm text-primary hover:underline">
83+
회원가입하기
84+
</Link>
85+
</div>
6286
</form>
6387
</CardContent>
6488
</Card>

0 commit comments

Comments
 (0)