---
title: 플러터에서 Parse 사용자 로그인/로그아웃 구현 방법
slug: docs-kr/flutter/parse-sdk/users/flutter-login
description: Flutter Parse SDK를 활용한 사용자 로그인/로그아웃 기술 구현 가이드.
image: https://www.back4app.com/images/logo-social.png
createdAt: 2024-03-18T13:24:43.792Z
---

# 플러터에서 파스 서버를 사용한 사용자 로그인 및 로그아웃

## 소개

지난 가이드에서 파스를 사용한 플러터의 사용자 등록을 구현한 후, 동일한 ParseUser 클래스를 사용하여 사용자를 로그인하고 로그아웃하는 방법을 배우게 됩니다. 가입 후, 로그인 작업이 자동으로 수행되며 새로운 사용자 세션이 생성됩니다. 로그아웃 작업은 로그인한 사용자의 활성 세션 객체를 삭제합니다.

이 가이드에서는 **Parse Server를 위한 Flutter 플러그인**을 사용하여 플러터 앱에서 ParseUser 클래스를 사용하여 로그인/로그아웃을 수행하는 방법을 배우게 됩니다.

## 목표

플러터 앱을 위한 사용자 로그인/로그아웃 기능을 파스를 사용하여 구축하는 것입니다.

## 전제 조건

**이 튜토리얼을 완료하려면 다음이 필요합니다:**

:::hint{type="info"}
- [Flutter 버전 2.2.x 이상](https://flutter.dev/docs/get-started/install)
- [Android Studio ](https://developer.android.com/studio) 또는 [VS Code 설치](https://code.visualstudio.com/) (과 [플러그인](https://docs.flutter.dev/get-started/editor) Dart 및 Flutter)
- Back4App에서 [생성된](https://www.back4app.com/docs/get-started/new-parse-app) 앱:
  - **참고:&#x20;**&#x20;[새 Parse 앱 튜토리얼](https://www.back4app.com/docs/get-started/new-parse-app)을 따라 Back4App에서 Parse 앱을 만드는 방법을 배우세요.
- Back4app에 연결된 Flutter 앱.
  - **참고:&#x20;**&#x20;[Flutter 프로젝트에 Parse SDK 설치](https://www.back4app.com/docs/flutter/parse-sdk/parse-flutter-sdk)하여 Back4App에 연결된 Flutter 프로젝트를 만드세요.
- 이전 가이드를 완료하여 <font color="#2166ae">`ParseUser`</font> 클래스에 대한 더 나은 이해를 얻으세요.
- Android 또는 iOS에서 실행되는 장치(또는 가상 장치).
:::

## 로그인/로그아웃 앱 이해하기

로그인/로그아웃 프로세스를 더 잘 이해하기 위해, 우리는 사용자가 귀하의 계정에 로그인하고 로그아웃할 수 있는 앱을 만들 것입니다.

이 가이드의 주요 초점이 Flutter와 Parse를 사용하는 것이기 때문에 Flutter 애플리케이션 코드는 설명하지 않겠습니다. 다음 단계를 따르면 Back4App 데이터베이스에서 로그인 및 로그아웃 앱을 구축할 수 있습니다.

## 시작해 봅시다!

다음 단계에서는 로그인/로그아웃 앱을 만들 수 있습니다.

## 1 - 로그인/로그아웃 앱 템플릿 만들기

이전 가이드에서 Flutter 프로젝트를 엽니다 **Parse Server용 Flutter 플러그인**. <font color="#2166ae">`main.dart`</font> 파일을 열고 모든 코드를 정리한 후 다음으로 교체합니다:

```dart
1   import 'package:flutter/material.dart';
2   import 'package:parse_server_sdk_flutter/parse_server_sdk.dart';
3
4   void main() async {
5     WidgetsFlutterBinding.ensureInitialized();
6 
7     final keyApplicationId = 'YOUR_APP_ID_HERE';
8     final keyClientKey = 'YOUR_CLIENT_KEY_HERE';
9     final keyParseServerUrl = 'https://parseapi.back4app.com';
10
11    await Parse().initialize(keyApplicationId, keyParseServerUrl,
12        clientKey: keyClientKey, debug: true);
13
14    runApp(MyApp());
15  }
16
17  class MyApp extends StatelessWidget {
18    @override
19    Widget build(BuildContext context) {
20      return MaterialApp(
21        title: 'Flutter Login/Logout',
22        theme: ThemeData(
23          primarySwatch: Colors.blue,
24          visualDensity: VisualDensity.adaptivePlatformDensity,
25        ),
26        home: HomePage(),
27      );
28    }
29  }
30  
31  class HomePage extends StatefulWidget {
32    @override
33    _HomePageState createState() => _HomePageState();
34  }
35  
36  class _HomePageState extends State<HomePage> {
37    final controllerUsername = TextEditingController();
38    final controllerPassword = TextEditingController();
39    bool isLoggedIn = false;
40  
41    @override
42    Widget build(BuildContext context) {
43      return Scaffold(
44          appBar: AppBar(
45            title: const Text('Flutter Login/Logout'),
46          ),
47          body: Center(
48            child: SingleChildScrollView(
49              padding: const EdgeInsets.all(8),
50              child: Column(
51                crossAxisAlignment: CrossAxisAlignment.stretch,
52                children: [
53                  Container(
54                    height: 200,
55                    child: Image.network(
56                        'http://blog.back4app.com/wp-content/uploads/2017/11/logo-b4a-1-768x175-1.png'),
57                  ),
58                  Center(
59                    child: const Text('Flutter on Back4App',
60                        style:
61                            TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
62                  ),
63                  SizedBox(
64                    height: 16,
65                  ),
66                  Center(
67                    child: const Text('User Login/Logout',
68                        style: TextStyle(fontSize: 16)),
69                  ),
70                  SizedBox(
71                    height: 16,
72                  ),
73                  TextField(
74                    controller: controllerUsername,
75                    enabled: !isLoggedIn,
76                    keyboardType: TextInputType.text,
77                    textCapitalization: TextCapitalization.none,
78                    autocorrect: false,
79                    decoration: InputDecoration(
80                        border: OutlineInputBorder(
81                            borderSide: BorderSide(color: Colors.black)),
82                        labelText: 'Username'),
83                  ),
84                  SizedBox(
85                    height: 8,
86                  ),
87                  TextField(
88                    controller: controllerPassword,
89                    enabled: !isLoggedIn,
90                    obscureText: true,
91                    keyboardType: TextInputType.text,
92                    textCapitalization: TextCapitalization.none,
93                    autocorrect: false,
94                    decoration: InputDecoration(
95                        border: OutlineInputBorder(
96                            borderSide: BorderSide(color: Colors.black)),
97                        labelText: 'Password'),
98                  ),
99                  SizedBox(
100                   height: 16,
101                 ),
102                 Container(
103                   height: 50,
104                   child: TextButton(
105                     child: const Text('Login'),
106                     onPressed: isLoggedIn ? null : () => doUserLogin(),
107                   ),
108                 ),
109                 SizedBox(
110                   height: 16,
111                 ),
112                 Container(
113                  height: 50,
114                   child: TextButton(
115                     child: const Text('Logout'),
116                     onPressed: !isLoggedIn ? null : () => doUserLogout(),
117                   ),
118                 )
119               ],
120             ),
121           ),
122         ));
123   }
124 
125   void showSuccess(String message) {
126     showDialog(
127       context: context,
128       builder: (BuildContext context) {
129         return AlertDialog(
130           title: const Text("Success!"),
131           content: Text(message),
132           actions: <Widget>[
133             new TextButton(
134               child: const Text("OK"),
135               onPressed: () {
136                 Navigator.of(context).pop();
137               },
138             ),
139           ],
140         );
141       },
142     );
143   }
144 
145   void showError(String errorMessage) {
146     showDialog(
147       context: context,
148       builder: (BuildContext context) {
149         return AlertDialog(
150           title: const Text("Error!"),
151           content: Text(errorMessage),
152           actions: <Widget>[
153             new TextButton(
154               child: const Text("OK"),
155               onPressed: () {
156                 Navigator.of(context).pop();
157               },
158             ),
159           ],
160         );
161       },
162     );
163   }
164 
165   void doUserLogin() async {
166    
167   }
168 
169   void doUserLogout() async {
170    
171   }
172 }
173
```

:::hint{type="info"}
함수 <font color="#2166ae">`debug`</font>의 <font color="#2166ae">`Parse().initialize`</font> 매개변수가 <font color="#2166ae">`true`</font>, Parse API 호출을 콘솔에 표시할 수 있습니다. 이 설정은 코드 디버깅에 도움이 될 수 있습니다. 릴리스 버전에서는 디버그를 비활성화하는 것이 좋습니다.
:::

## 2 - 템플릿을 Back4app 프로젝트에 연결하기

애플리케이션 ID와 클라이언트 키 자격 증명을 찾으려면 [Back4App 웹사이트](https://www.back4app.com/)로 이동하여 앱 대시보드에서 확인하세요.

코드를 <font color="#2166ae">`main.dart`</font>에서 Back4app의 애플리케이션 ID와 클라이언트 키 값으로 업데이트하세요.

- **keyApplicationId = 앱 ID**
- **keyClientKey = 클라이언트 키**

프로젝트를 실행하면 앱이 이미지와 같이 로드됩니다.

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/VE1p8XtbVl9YvxJ4oH470_image.png" size="50" width="321" height="635" position="center" showCaption="false"}

## 3 - 사용자 로그인 코드

사용자 로그인 기능은 <font color="#2166ae">`세션`</font> 객체를 생성하여 <font color="#2166ae">`로그인한 사용자`</font>를 가리키고 유효한 사용자 세션을 로컬 스토리지에 저장합니다.

향후 <font color="#2166ae">`currentUser`</font>와 같은 메서드 호출은 성공적으로 <font color="#2166ae">`사용자`</font> 데이터를 검색하고 <font color="#2166ae">`sessionToken`</font>을 <font color="#2166ae">`세션`</font> 객체에 대해 생성된 <font color="#2166ae">`대시보드`</font>에서 가져옵니다.

파일 <font color="#2166ae">`main.dart`</font>에서 함수 <font color="#2166ae">`doUserLogin`</font>을 검색합니다. <font color="#2166ae">`doUserLogin`</font> 내부의 코드를 다음으로 교체합니다:

```dart
1   final username = controllerUsername.text.trim();
2       final password = controllerPassword.text.trim();
3
4       final user = ParseUser(username, password, null);
5 
6       var response = await user.login();
7
8       if (response.success) {
9         showSuccess("User was successfully login!");
10        setState(() {
11          isLoggedIn = true;
12        });
13      } else {
14        showError(response.error!.message);
15      }
```

이 기능을 구축하려면 다음 단계를 따르세요:

1. 새로운<font color="#2166ae">`ParseUser`</font> 클래스 인스턴스를 다음 명령으로 생성합니다: <font color="#2166ae">`ParseUser(username, password, null);`</font> 앱에 입력된 데이터를 사용하여. 이메일 필드는 필요하지 않으며 null로 입력해야 합니다.
2. 다음의<font color="#2166ae">`login`</font> 함수를 호출합니다. 이 함수는 <font color="#2166ae">`Session`</font>을(를) Parse 대시보드의 데이터베이스에 생성하고 토큰을 로컬 저장소에 저장합니다.
3. 사용자 로그인이 성공했는지 확인합니다. 성공하지 않았다면 오류 설명 메시지를 표시합니다.

완전한 함수는 다음과 같아야 합니다:

```dart
1     void doUserLogin() async {
2       final username = controllerUsername.text.trim();
3       final password = controllerPassword.text.trim();
4
5       final user = ParseUser(username, password, null);
6
7       var response = await user.login();
8
9       if (response.success) {
10        showSuccess("User was successfully login!");
11        setState(() {
12          isLoggedIn = true;
13        });
14      } else {
15        showError(response.error!.message);
16      }
17    }
```

:::hint{type="info"}
테스트하려면 Android Studio/VSCode에서 <font color="#2166ae">`Run`</font> 버튼을 클릭하세요.
:::

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/Z8Z2CgsB7YUKk4tJ91_4F_image.png" size="50" width="321" height="635" position="center" showCaption="false"}

원하는 사용자 자격 증명을 제공한 후, 로그인 버튼을 눌렀을 때 모든 것이 성공적이라면 이 메시지를 볼 수 있습니다:

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/Bw7YyqHurBgLJCvBg9EYq_image.png" size="50" width="321" height="635" position="center" showCaption="false"}

잘못된 자격 증명으로 사용자를 로그인하려고 하면 오류 처리를 테스트할 수 있습니다:

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/SaBJxLYqWUo9ua2rIN1O6_image.png" size="50" width="321" height="635" position="center" showCaption="false"}

비밀번호 없이 로그인하려고 하면 또 다른 오류가 발생합니다:

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/odoAAZAaQk60dIyGy_g6m_image.png" size="50" width="321" height="635" position="center" showCaption="false"}

## 4 - 사용자 로그아웃 코드

사용자 로그아웃 기능은 <font color="#2166ae">`세션`</font> 객체를 삭제합니다. 이 객체는 로그인 기능에서 생성되었습니다. 이 세션은 장치에서 지워지고 Parse 서버의 모든 연결된 서비스에서 로그아웃됩니다.

함수 <font color="#2166ae">`doUserLogout`</font>를 파일 <font color="#2166ae">`main.dart`</font>. <font color="#2166ae">`doUserLogout`</font>의 코드를 다음으로 교체하세요:

```dart
1       final user = await ParseUser.currentUser() as ParseUser;
2       var response = await user.logout();
3
4       if (response.success) {
5         showSuccess("User was successfully logout!");
6         setState(() {
7           isLoggedIn = false;
8         });
9       } else {
10        showError(response.error!.message);
11      }
```

이 함수를 만들기 위해 다음 단계를 따르세요:

1. 함수를 사용하여 현재 로그인된 사용자를 가져옵니다.<font color="#2166ae">`ParseUser.currentUser()`</font>.
2. 다음에 대해 <font color="#2166ae">`logout`</font> 함수를 호출합니다.<font color="#2166ae">`ParseUser`</font> 객체는 데이터베이스에서 <font color="#2166ae">`Session`</font>을 삭제하고 로컬 저장소의 토큰을 정리합니다.
3. 사용자 로그아웃이 성공했는지 확인합니다. 성공하지 않았다면 오류 설명 메시지를 표시합니다.

전체 코드는 다음과 같아야 합니다:

```dart
1     void doUserLogout() async {
2       final user = await ParseUser.currentUser() as ParseUser;
3       var response = await user.logout();
4   
5       if (response.success) {
6         showSuccess("User was successfully logout!");
7         setState(() {
8           isLoggedIn = false;
9         });
10      } else {
11        showError(response.error!.message);
12      }
13    }
```

:::hint{type="info"}
테스트하려면 Android Studio/VSCode에서 <font color="#2166ae">`Run`</font> 버튼을 클릭하세요.
:::

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/6T1LA_tKJ9CZ15grhE7Vj_image.png" size="50" width="321" height="635" position="center" showCaption="false"}

원하는 사용자 자격 증명을 제공한 후, 모든 것이 성공적이었다면 로그인 버튼을 누른 후 이 메시지를 볼 수 있습니다:

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/GBTX41Q1jYmHMHrKfTGU2_image.png" size="50" width="321" height="635" position="center" showCaption="false"}

“로그아웃” 버튼을 클릭하세요:

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/Yq2P3Vt15tCf75963iJZv_image.png" size="50" width="321" height="635" position="center" showCaption="false"}

## 완료되었습니다!

이 가이드의 끝에서, Back4App을 통해 Parse Server의 핵심 기능을 사용하여 앱의 Parse 사용자에 로그인하고 로그아웃할 수 있습니다!
