카테고리 없음
32일차
신승호.
2023. 3. 12. 21:11
- Getx AuthController 강의를 보고 따라서 제작하시오.
- AuthController에는 User의 정보만을 담고있다. 로그인을 하면 유저를 식별할 수 있는 Token 값도 함께 받아볼 수 있는데, 해당 Token 값을 AuthController 내에 저장할 수 있도록 하고, 코드를 제시하시오.
- 해당 API의 정보는 다음과 같다
- API URL
- // <http://52.79.115.43:8090/api/collections/users/auth-with-password>
- API Request
- // Method : POST // data : identity(String), password(String) // Teddy/sfac12341234
- API Response
- 해당 API의 정보는 다음과 같다
{
"token": "JWT_TOKEN",
"record": {
"id": "RECORD_ID",
"collectionId": "_pb_users_auth_",
"collectionName": "users",
"created": "2022-01-01 01:00:00Z",
"updated": "2022-01-01 23:59:59Z",
"username": "username123",
"verified": false,
"emailVisibility": true,
"email": "test@example.com",
"name": "test",
"avatar": "filename.jpg"
}
}
- MainController에는 readDocuments라는 멤버 함수(메서드)를 제작하시오.
- 해당 API의 정보는 다음과 같다 이 때, AuthController를 find하여 Token값이 존재하면 (로그인 되었다면) 실행할 수 있도록 한다.
- API URL
- // <http://52.79.115.43:8090/api/collections/documents/records>
- API Request (필수)
- // Method: GET
// 해당 API는 인증된 사용자만 사용할 수 있기 때문에
// 로그인 시 획득한 Token을 반드시 Request 헤더에 Authorization을 포함시켜야만합니다.
- API Response (성공시)
- 해당 API의 정보는 다음과 같다 이 때, AuthController를 find하여 Token값이 존재하면 (로그인 되었다면) 실행할 수 있도록 한다.
- 위 API 정보를 토대로 응답 데이터형식에 맞게 Document 커스텀 클래스를 제작하고, MainPage의 Home이 다음과 같이 출력되도록 한다.
- 아래 FAB를 누르면 readDocuments를 실행하고 결과를 화면에 출력한다.
- document리스트는 MainController 멤버변수로 저장한다.
- 다음의 제공되는 코드를 사용할 수 있도록 한다.
- /lib/model/document.dart
// ignore_for_file: public_member_api_docs, sort_constructors_first, non_constant_identifier_names
class Document {
String title;
String content;
String sec_level;
String? attachment_url;
Document({
required this.title,
required this.content,
required this.sec_level,
this.attachment_url,
});
factory Document.fromMap(Map<String, dynamic> map) {
return Document(
title: map['title'] as String,
content: map['content'] as String,
sec_level: map['sec_level'] as String,
attachment_url:
map['attachment_url'] != '' ? map['attachment_url'] : null,
);
}
}
lib/controller/auth_controller.dart
import 'package:dio/dio.dart';
import 'package:get/get.dart';
import 'package:myapp32/model/user.dart';
import 'package:myapp32/util/api_routes.dart';
import 'package:myapp32/util/app_routes.dart';
class AuthController extends GetxController {
final Rxn<User> _user = Rxn();
Dio dio = Dio();
String? _token;
User? get user => _user.value; //user를 불러오면 _user의 value를 전달해
String? get token => _token; //토큰 전달
login(String id, String pw) async {
try {
var res = await dio.post(
'http://52.79.115.43:8090${ApiRoutes.authWithPassword}',
data: {'identity': id, 'password': pw}); //데이터따로관리해준
if (res.statusCode == 200) {
var user = User.fromMap(res.data['record']);
_user(user); //유저정보 저장
_token = res.data['token']; //토큰저장
}
} on DioError catch (e) {
print(e.message);
}
}
logout() {
_user.value = null;
}
_handleAuthChanged(User? data) {
if (data != null) {
//메인페이지 이동
Get.toNamed(AppRoutes.main);
return;
}
//로그인페이지 이동
Get.toNamed(AppRoutes.login);
return;
}
@override
void onInit() {
super.onInit();
ever(_user, _handleAuthChanged);
}
}
token...어케하지 눈치것 썼는데..
lib/controller/login_controller.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:myapp32/controller/auth_controller.dart';
class Logincontroller extends GetxController {
var idController = TextEditingController();
var pwController = TextEditingController();
login() {
Get.find<AuthController>().login(idController.text, pwController.text);
//Authcontroller는 전역에서 사용가능하기 때문에 find할수있게됨
}
}
lib/controller/main_controller.dart
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:myapp32/controller/auth_controller.dart';
import 'package:myapp32/model/document.dart';
import 'package:myapp32/util/api_routes.dart';
class MainController extends GetxController {
var pageController = PageController();
RxInt curPage = 0.obs;
RxList<Document> documents = RxList();
Dio dio = Dio();
onPageTapped(int v) {
pageController.jumpToPage(v);
curPage(v);
}
logout() {
Get.find<AuthController>().logout();
}
readDocuments() async {
dio.options.baseUrl = 'http://52.79.115.43:8090';
var token = Get.find<AuthController>().token;
try {
documents.clear();
var res = await dio.get(ApiRoutes.documents,
options: Options(headers: {'authorization': token}),
data: {token: token});
if (res.statusCode == 200) {
List<Map<String, dynamic>> data =
List<Map<String, dynamic>>.from(res.data['items']);
documents.addAll(data.map((e) => Document.fromMap(e)).toList().obs);
}
} on DioError catch (e) {
print(e.message);
}
}
}
lib/model/document.dart 고대로 사용함
// ignore_for_file: public_member_api_docs, sort_constructors_first, non_constant_identifier_names
class Document {
String title;
String content;
String sec_level;
String? attachment_url;
Document({
required this.title,
required this.content,
required this.sec_level,
this.attachment_url,
});
factory Document.fromMap(Map<String, dynamic> map) {
return Document(
title: map['title'] as String,
content: map['content'] as String,
sec_level: map['sec_level'] as String,
attachment_url:
map['attachment_url'] != '' ? map['attachment_url'] : null,
);
}
}
lib/model/user.dart
// ignore_for_file: public_member_api_docs, sort_constructors_first, non_constant_identifier_names
class Document {
String title;
String content;
String sec_level;
String? attachment_url;
Document({
required this.title,
required this.content,
required this.sec_level,
this.attachment_url,
});
factory Document.fromMap(Map<String, dynamic> map) {
return Document(
title: map['title'] as String,
content: map['content'] as String,
sec_level: map['sec_level'] as String,
attachment_url:
map['attachment_url'] != '' ? map['attachment_url'] : null,
);
}
}
lib/util/api_routes.dart
//Api가 계속 늘어날수도 있기때문에 따로 관리해줌
class ApiRoutes {
static const String authWithPassword =
'/api/collections/users/auth-with-password';
static const String documents = '/api/collections/documents/records';
}
lib/util/app_routes.dart
import 'package:myapp32/view/login_page.dart';
import 'package:myapp32/view/main_page.dart';
class AppRoutes {
static const main = MainPage.route; //메인 페이지 라우트
static const login = LoginPage.route; //로그인 페이지 라우트
}
lib/util/apppages.dart
import 'package:get/get.dart';
import 'package:myapp32/util/app_routes.dart';
import 'package:myapp32/view/login_page.dart';
import 'package:myapp32/view/main_page.dart';
class AppPages {
static final pages = [
GetPage(name: AppRoutes.main, page: () => const MainPage()),
GetPage(name: AppRoutes.login, page: () => const LoginPage()),
];
}
lib/view/main_page.dart
// ignore_for_file: prefer_const_constructors
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:myapp32/controller/auth_controller.dart';
import 'package:myapp32/controller/main_controller.dart';
import 'package:myapp32/view/homescreen.dart';
import 'package:myapp32/view/myscreen.dart';
class MainPage extends GetView<MainController> {
const MainPage({super.key});
static const String route = '/main';
@override
Widget build(BuildContext context) {
var user = Get.find<AuthController>().user;
return Scaffold(
body: SafeArea(
child: PageView(
controller: controller.pageController,
children: [
//Home페이지
Obx(() =>
HomeScreen(document: controller.documents.toList(), user: user!)),
//My페이지
MyScreen(user: user!, onTap: controller.logout)
],
)),
bottomNavigationBar: Obx(
() => BottomNavigationBar(
currentIndex: controller.curPage.value,
onTap: controller.onPageTapped,
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.home,
),
label: 'Home'),
BottomNavigationBarItem(
icon: Icon(
Icons.person,
),
label: 'My')
]),
),
floatingActionButton: Obx((() {
if (controller.curPage.value == 0) {
return FloatingActionButton(
onPressed: controller.readDocuments,
child: Icon(Icons.refresh),
);
}
return SizedBox();
})),
);
}
}
lib/view/login_page.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:myapp32/controller/login_controller.dart';
class LoginPage extends GetView<Logincontroller> {
const LoginPage({super.key});
static const String route = '/login';
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: controller.idController,
),
TextField(
controller: controller.pwController,
),
ElevatedButton(onPressed: controller.login, child: Text('로그인하기'))
],
),
),
);
}
}
lib/view/homescreen
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:myapp32/controller/login_controller.dart';
class LoginPage extends GetView<Logincontroller> {
const LoginPage({super.key});
static const String route = '/login';
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: controller.idController,
),
TextField(
controller: controller.pwController,
),
ElevatedButton(onPressed: controller.login, child: Text('로그인하기'))
],
),
),
);
}
}
lib/view/myscreen
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:get/get.dart';
import 'package:myapp32/controller/auth_controller.dart';
import 'package:myapp32/model/user.dart';
class MyScreen extends StatelessWidget {
const MyScreen({
super.key,
required this.user,
required this.onTap,
});
final User user;
final VoidCallback onTap; //입력 인자가 없는 함수를 호출할 수 있는 타입
@override
Widget build(BuildContext context) {
var user = Get.find<AuthController>().user!;
return Scaffold(
body: //My페이지
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
ListTile(
title: Text(user.username),
subtitle: Text(user.name),
),
ListTile(
title: Text('로그아웃'),
leading: Icon(Icons.logout),
onTap: onTap,
),
]));
}
}
main.dart
// ignore_for_file: prefer_const_constructors
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:myapp32/controller/auth_controller.dart';
import 'package:myapp32/controller/login_controller.dart';
import 'package:myapp32/controller/main_controller.dart';
import 'package:myapp32/util/app_routes.dart';
import 'package:myapp32/util/apppages.dart';
import 'package:myapp32/view/login_page.dart';
import 'package:myapp32/view/main_page.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return GetMaterialApp(
initialBinding: BindingsBuilder(() {
Get.put(AuthController()); //initialBinding이 실행되면서 Get.put이실행됨
Get.lazyPut(() => Logincontroller());
Get.lazyPut(
() => MainController(),
);
}),
getPages: AppPages.pages,
home: Scaffold(
body: Center(
child: TextButton(
onPressed: () => Get.toNamed(AppRoutes.login),
child: Text('로그인페이지로 가실?'),
),
),
),
);
}
}
어려운데 할만한거 같기도 하고...
내용정리를 아직못해서 시간이 더 걸릴거다..