Flutter
...
Authentication
Flutter Parse 서버 현재 세션 사용자 구현 가이드
13 분
현재 세션의 사용자 가져오기 소개 사용자가 앱을 열 때마다 로그인해야 한다면 즐겁지 않을 것입니다 현재 parseuser 객체를 캐시하여 이를 피할 수 있습니다 회원가입 또는 로그인 메서드를 사용할 때마다 사용자가 로컬에 캐시됩니다 이 캐시를 세션으로 관리하고 사용자가 자동으로 로그인했다고 가정할 수 있습니다 이 가이드에서는 flutter 앱을 위해 parseuser 클래스를 사용하여 현재 세션의 사용자를 가져오는 방법을 배우게 됩니다 parse server용 flutter 플러그인 을 사용하여 현재 세션의 사용자를 가져오는 방법 목표 flutter 앱을 위해 parse를 사용하여 현재 세션의 사용자를 가져옵니다 전제 조건 이 튜토리얼을 완료하려면 다음이 필요합니다 flutter 버전 2 2 x 이상 https //flutter dev/docs/get started/install android studio https //developer android com/studio 또는 vs code 설치 (이와 함께 플러그인 dart 및 flutter) back4app에 연결된 flutter 앱 참고 flutter 프로젝트에 parse sdk 설치 를 따라 back4app에 연결된 flutter 프로젝트를 생성하세요 이전 가이드를 완료하여 parseuser parseuser 클래스에 대한 이해를 높이세요 android 또는 ios에서 실행되는 장치(시뮬레이터 아님) 현재 사용자 앱 이해하기 현재 사용자 세션 프로세스를 더 잘 이해하기 위해, 사용자를 가입시키고, 로그인하고, 로그아웃하는 앱을 만들 것입니다 이 애플리케이션은 이전 가이드와 유사하며, 가입, 로그인 및 로그아웃을 수행합니다 다음 가이드에서 동일한 프로젝트를 사용할 것이므로, 아직 사용 가능한 기능이 없을 수 있습니다 이 가이드의 주요 초점은 flutter와 parse를 사용하는 것이므로 flutter 애플리케이션 코드는 설명하지 않겠습니다 다음 단계에 따라 back4app 데이터베이스에서 로그인 및 로그아웃 앱을 구축할 것입니다 시작해봅시다! 다음 단계에서 현재 사용자를 가져오는 앱을 구축할 수 있습니다 1 로그인/로그아웃 앱 템플릿 만들기 이전 가이드에서 flutter 프로젝트를 엽니다 parse server용 flutter 플러그인 main 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, 13 debug true); 14 15 runapp(myapp()); 16 } 17 18 class myapp extends statelesswidget { 19 future\<bool> hasuserlogged() async { 20 return future value(false); 21 } 22 23 @override 24 widget build(buildcontext context) { 25 return materialapp( 26 title 'flutter parse server', 27 theme themedata( 28 primaryswatch colors blue, 29 visualdensity visualdensity adaptiveplatformdensity, 30 ), 31 home futurebuilder\<bool>( 32 future hasuserlogged(), 33 builder (context, snapshot) { 34 switch (snapshot connectionstate) { 35 case connectionstate none 36 case connectionstate waiting 37 return scaffold( 38 body center( 39 child container( 40 width 100, 41 height 100, 42 child circularprogressindicator()), 43 ), 44 ); 45 default 46 if (snapshot hasdata && snapshot data!) { 47 return userpage(); 48 } else { 49 return loginpage(); 50 } 51 } 52 }), 53 ); 54 } 55 } 56 57 class loginpage extends statefulwidget { 58 @override 59 loginpagestate createstate() => loginpagestate(); 60 } 61 62 class loginpagestate extends state\<loginpage> { 63 final controllerusername = texteditingcontroller(); 64 final controllerpassword = texteditingcontroller(); 65 bool isloggedin = false; 66 67 @override 68 widget build(buildcontext context) { 69 return scaffold( 70 appbar appbar( 71 title const text('flutter parse server'), 72 ), 73 body center( 74 child singlechildscrollview( 75 padding const edgeinsets all(8), 76 child column( 77 crossaxisalignment crossaxisalignment stretch, 78 children \[ 79 container( 80 height 200, 81 child image network( 82 'https //blog back4app com/wp content/uploads/2017/11/logo b4a 1 768x175 1 png'), 83 ), 84 center( 85 child const text('flutter on back4app', 86 style 87 textstyle(fontsize 18, fontweight fontweight bold)), 88 ), 89 sizedbox( 90 height 16, 91 ), 92 textfield( 93 controller controllerusername, 94 enabled !isloggedin, 95 keyboardtype textinputtype text, 96 textcapitalization textcapitalization none, 97 autocorrect false, 98 decoration inputdecoration( 99 border outlineinputborder( 100 borderside borderside(color colors black)), 101 labeltext 'username'), 102 ), 103 sizedbox( 104 height 8, 105 ), 106 textfield( 107 controller controllerpassword, 108 enabled !isloggedin, 109 obscuretext true, 110 keyboardtype textinputtype text, 111 textcapitalization textcapitalization none, 112 autocorrect false, 113 decoration inputdecoration( 114 border outlineinputborder( 115 borderside borderside(color colors black)), 116 labeltext 'password'), 117 ), 118 sizedbox( 119 height 16, 120 ), 121 container( 122 height 50, 123 child elevatedbutton( 124 child const text('login'), 125 onpressed isloggedin ? null () => douserlogin(), 126 ), 127 ), 128 sizedbox( 129 height 16, 130 ), 131 container( 132 height 50, 133 child elevatedbutton( 134 child const text('sign up'), 135 onpressed () => navigatetosignup(), 136 ), 137 ), 138 sizedbox( 139 height 16, 140 ), 141 container( 142 height 50, 143 child elevatedbutton( 144 child const text('reset password'), 145 onpressed () => navigatetoresetpassword(), 146 ), 147 ) 148 ), 149 ), 150 ), 151 )); 152 } 153 154 void douserlogin() async { 155 final username = controllerusername text trim(); 156 final password = controllerpassword text trim(); 157 158 final user = parseuser(username, password, null); 159 160 var response = await user login(); 161 162 if (response success) { 163 navigatetouser(); 164 } else { 165 message showerror(context context, message response error! message); 166 } 167 } 168 169 void navigatetouser() { 170 navigator pushandremoveuntil( 171 context, 172 materialpageroute(builder (context) => userpage()), 173 (route\<dynamic> route) => false, 174 ); 175 } 176 177 void navigatetosignup() { 178 navigator push( 179 context, 180 materialpageroute(builder (context) => signuppage()), 181 ); 182 } 183 184 void navigatetoresetpassword() { 185 navigator push( 186 context, 187 materialpageroute(builder (context) => resetpasswordpage()), 188 ); 189 } 190 } 191 192 class signuppage extends statefulwidget { 193 @override 194 signuppagestate createstate() => signuppagestate(); 195 } 196 197 class signuppagestate extends state\<signuppage> { 198 final controllerusername = texteditingcontroller(); 199 final controllerpassword = texteditingcontroller(); 200 final controlleremail = texteditingcontroller(); 201 202 @override 203 widget build(buildcontext context) { 204 return scaffold( 205 appbar appbar( 206 title const text('flutter sign up'), 207 ), 208 body center( 209 child singlechildscrollview( 210 padding const edgeinsets all(8), 211 child column( 212 crossaxisalignment crossaxisalignment stretch, 213 children \[ 214 container( 215 height 200, 216 child image network( 217 'https //blog back4app com/wp content/uploads/2017/11/logo b4a 1 768x175 1 png'), 218 ), 219 center( 220 child const text('flutter on back4app', 221 style 222 textstyle(fontsize 18, fontweight fontweight bold)), 223 ), 224 sizedbox( 225 height 16, 226 ), 227 center( 228 child const text('user registration', 229 style textstyle(fontsize 16)), 230 ), 231 sizedbox( 232 height 16, 233 ), 234 textfield( 235 controller controllerusername, 236 keyboardtype textinputtype text, 237 textcapitalization textcapitalization none, 238 autocorrect false, 239 decoration inputdecoration( 240 border outlineinputborder( 241 borderside borderside(color colors black)), 242 labeltext 'username'), 243 ), 244 sizedbox( 245 height 8, 246 ), 247 textfield( 248 controller controlleremail, 249 keyboardtype textinputtype emailaddress, 250 textcapitalization textcapitalization none, 251 autocorrect false, 252 decoration inputdecoration( 253 border outlineinputborder( 254 borderside borderside(color colors black)), 255 labeltext 'e mail'), 256 ), 257 sizedbox( 258 height 8, 259 ), 260 textfield( 261 controller controllerpassword, 262 obscuretext true, 263 keyboardtype textinputtype text, 264 textcapitalization textcapitalization none, 265 autocorrect false, 266 decoration inputdecoration( 267 border outlineinputborder( 268 borderside borderside(color colors black)), 269 labeltext 'password'), 270 ), 271 sizedbox( 272 height 8, 273 ), 274 container( 275 height 50, 276 child elevatedbutton( 277 child const text('sign up'), 278 onpressed () => douserregistration(), 279 ), 280 ) 281 ], 282 ), 283 ), 284 )); 285 } 286 287 void douserregistration() async { 288 final username = controllerusername text trim(); 289 final email = controlleremail text trim(); 290 final password = controllerpassword text trim(); 291 292 final user = parseuser createuser(username, password, email); 293 294 var response = await user signup(); 295 296 if (response success) { 297 message showsuccess( 298 context context, 299 message 'user was successfully created!', 300 onpressed () async { 301 navigator pushandremoveuntil( 302 context, 303 materialpageroute(builder (context) => userpage()), 304 (route\<dynamic> route) => false, 305 ); 306 }); 307 } else { 308 message showerror(context context, message response error! message); 309 } 310 } 311 } 312 313 class userpage extends statelesswidget { 314 parseuser? currentuser; 315 316 future\<parseuser?> getuser() async { 317 } 318 319 @override 320 widget build(buildcontext context) { 321 void douserlogout() async { 322 var response = await currentuser! logout(); 323 if (response success) { 324 message showsuccess( 325 context context, 326 message 'user was successfully logout!', 327 onpressed () { 328 navigator pushandremoveuntil( 329 context, 330 materialpageroute(builder (context) => loginpage()), 331 (route\<dynamic> route) => false, 332 ); 333 }); 334 } else { 335 message showerror(context context, message response error! message); 336 } 337 } 338 339 return scaffold( 340 appbar appbar( 341 title text('user logged in current user'), 342 ), 343 body futurebuilder\<parseuser?>( 344 future getuser(), 345 builder (context, snapshot) { 346 switch (snapshot connectionstate) { 347 case connectionstate none 348 case connectionstate waiting 349 return center( 350 child container( 351 width 100, 352 height 100, 353 child circularprogressindicator()), 354 ); 355 default 356 return padding( 357 padding const edgeinsets all(8 0), 358 child column( 359 crossaxisalignment crossaxisalignment stretch, 360 mainaxisalignment mainaxisalignment center, 361 children \[ 362 center( 363 child text('hello, ${snapshot data! username}')), 364 sizedbox( 365 height 16, 366 ), 367 container( 368 height 50, 369 child elevatedbutton( 370 child const text('logout'), 371 onpressed () => douserlogout(), 372 ), 373 ), 374 ], 375 ), 376 ); 377 } 378 })); 379 } 380 } 381 382 class resetpasswordpage extends statefulwidget { 383 @override 384 resetpasswordpagestate createstate() => resetpasswordpagestate(); 385 } 386 387 class resetpasswordpagestate extends state\<resetpasswordpage> { 388 final controlleremail = texteditingcontroller(); 389 390 @override 391 widget build(buildcontext context) { 392 return scaffold( 393 appbar appbar( 394 title text('reset password'), 395 ), 396 body singlechildscrollview( 397 padding const edgeinsets all(8), 398 child column( 399 crossaxisalignment crossaxisalignment stretch, 400 children \[ 401 textfield( 402 controller controlleremail, 403 keyboardtype textinputtype emailaddress, 404 textcapitalization textcapitalization none, 405 autocorrect false, 406 decoration inputdecoration( 407 border outlineinputborder( 408 borderside borderside(color colors black)), 409 labeltext 'e mail'), 410 ), 411 sizedbox( 412 height 8, 413 ), 414 container( 415 height 50, 416 child elevatedbutton( 417 child const text('reset password'), 418 onpressed () => douserresetpassword(), 419 ), 420 ) 421 ], 422 ), 423 )); 424 } 425 426 void douserresetpassword() async {} 427 } 428 429 class message { 430 static void showsuccess( 431 {required buildcontext context, 432 required string message, 433 voidcallback? onpressed}) { 434 showdialog( 435 context context, 436 builder (buildcontext context) { 437 return alertdialog( 438 title const text("success!"), 439 content text(message), 440 actions \<widget>\[ 441 new elevatedbutton( 442 child const text("ok"), 443 onpressed () { 444 navigator of(context) pop(); 445 if (onpressed != null) { 446 onpressed(); 447 } 448 }, 449 ), 450 ], 451 ); 452 }, 453 ); 454 } 455 456 static void showerror( 457 {required buildcontext context, 458 required string message, 459 voidcallback? onpressed}) { 460 showdialog( 461 context context, 462 builder (buildcontext context) { 463 return alertdialog( 464 title const text("error!"), 465 content text(message), 466 actions \<widget>\[ 467 new elevatedbutton( 468 child const text("ok"), 469 onpressed () { 470 navigator of(context) pop(); 471 if (onpressed != null) { 472 onpressed(); 473 } 474 }, 475 ), 476 ], 477 ); 478 }, 479 ); 480 } 481 } 482 함수 debug debug 의 매개변수 parse() initialize parse() initialize 가 true true , parse api 호출을 콘솔에 표시할 수 있습니다 이 설정은 코드를 디버깅하는 데 도움이 될 수 있습니다 릴리스 버전에서는 디버그를 비활성화하는 것이 바람직합니다 2 템플릿을 back4app 프로젝트에 연결하기 앱 대시보드에서 back4app 웹사이트 https //www back4app com/ 로 이동하여 애플리케이션 id 및 클라이언트 키 자격 증명을 찾으세요 코드를 업데이트하세요 main dart main dart 에 back4app의 프로젝트의 applicationid와 clientkey 값을 사용하세요 keyapplicationid = 앱 id keyclientkey = 클라이언트 키 프로젝트를 실행하면 앱이 이미지와 같이 로드됩니다 3 세션에서 현재 사용자 가져오기 위한 코드 사용자 로그인 또는 가입 기능은 세션 세션 객체를 생성하여 사용자 사용자 가 로그인된 상태를 가리키고, 유효한 사용자 세션을 로컬 저장소에 저장합니다 메서드 호출 currentuser currentuser 는 당신의 parseuser parseuser 데이터와 sessiontoken sessiontoken 을 성공적으로 가져옵니다 session session 객체 파일 hasuserlogged hasuserlogged 에서 함수 main dart main dart 을 검색하세요 코드를 hasuserlogged hasuserlogged 안에 있는 코드로 교체하세요 1 parseuser? currentuser = await parseuser currentuser() as parseuser?; 2 if (currentuser == null) { 3 return false; 4 } 5 //checks whether the user's session token is valid 6 final parseresponse? parseresponse = 7 await parseuser getcurrentuserfromserver(currentuser sessiontoken!); 8 9 if (parseresponse? success == null || !parseresponse! success) { 10 //invalid session logout 11 await currentuser logout(); 12 return false; 13 } else { 14 return true; 15 } 이 기능을 구축하려면 다음 단계를 따르세요 다음의 parseuser currentuser() parseuser currentuser() 함수를 호출하여, 로컬 저장소에서 parseuser parseuser 객체를 반환받습니다 만약 parseuser parseuser 가 null이라면, 우리는 앱에서 활성 세션을 가진 사용자가 없습니다 만약 parseuser parseuser 가 null이 아니라면, 우리는 앱에서 활성 세션을 가진 사용자가 있습니다 사용자의 세션은 parse 서버에서 유효성을 검사해야 하며, 세션에는 수명이 있습니다 토큰이 유효하지 않으면, 현재 세션을 지우기 위해 로그아웃 함수를 호출해야 하며 사용자는 다시 로그인해야 합니다 완전한 함수는 다음과 같아야 합니다 1 future\<bool> hasuserlogged() async { 2 parseuser? currentuser = await parseuser currentuser() as parseuser?; 3 if (currentuser == null) { 4 return false; 5 } 6 //checks whether the user's session token is valid 7 final parseresponse? parseresponse = 8 await parseuser getcurrentuserfromserver(currentuser sessiontoken!); 9 10 if (parseresponse? success == null || !parseresponse! success) { 11 //invalid session logout 12 await currentuser logout(); 13 return false; 14 } else { 15 return true; 16 } 17 } 파일에서 함수 getuser getuser 를 찾으세요 main dart main dart 코드를 getuser getuser 로 교체하세요 1 currentuser = await parseuser currentuser() as parseuser?; 2 return currentuser; 이 함수를 만들기 위해 다음 단계를 따르세요 다음의 parseuser currentuser() parseuser currentuser() 함수를 호출하면, 로컬 저장소에서 parseuser parseuser 객체를 반환합니다 완전한 함수는 다음과 같아야 합니다 1 future\<parseuser> getuser() async { 2 currentuser = await parseuser currentuser() as parseuser?; 3 return currentuser; 4 } 테스트하려면, android studio/vscode에서 run run 버튼을 클릭하세요 회원가입 또는 로그인하면 다음 화면에 로그인한 사용자의 사용자 이름이 표시됩니다 애플리케이션을 종료하고 다시 실행하세요 유효한 사용자 세션이 확인되면, 사용자의 사용자 이름이 표시된 화면이 나타납니다 완료되었습니다! 이 가이드의 끝에서, back4app을 통해 parse server의 핵심 기능을 사용하여 앱의 세션에서 현재 사용자를 가져올 수 있습니다!