flutter(dart)

[flutter] flask 서버를 이용한 로그인 , 회원가입

칠구의 스터디 2024. 3. 15. 20:56

 

파이썬 - 회원가입 및 로그인 코드
from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS


app = Flask(__name__)
CORS(app)

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
db = SQLAlchemy(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20), unique=True, nullable=False)
    password = db.Column(db.String(128), nullable=False)
    name = db.Column(db.String(20), nullable=True)
    date = db.Column(db.String(80), nullable=True)
    gender = db.Column(db.String(20), nullable=False)

    def __repr__(self):
        return f'<User {self.username}>'
    
if __name__ == '__main__':
    with app.app_context():
        db.create_all()    

#회원가입 부분
@app.route('/sign', methods=['GET','POST'])
def sign():
    if request.method == 'POST':
        data = request.json  
        print("Received data:", data)
        
        username = data.get('username')
        password = data.get('password')
        name = data.get('name')
        date = data.get('date')
        gender = data.get('gender')

        existing_user = User.query.filter_by(username=username).first()
        if existing_user:
            return jsonify({'message': '중복됨'}), 409


        new_user = User(username=username, password=password, name=name, date=date, gender=gender)
        try:
            db.session.add(new_user)
            db.session.commit()
            return jsonify({'message': '회원가입 성공!!'}), 201
        except Exception as e:
            db.session.rollback()
            return jsonify({'message': '회원가입 실패 ㅠ.ㅠ'}), 500


#로그인 부분
@app.route('/login', methods=['GET','POST'])
def login():
    data = request.json
    print("Received data:", data)
    
    username = data.get('username')
    password = data.get('password')
    
    user = User.query.filter_by(username=username , password = password).first()
    if user:
            return jsonify({'message': '로그인 성공!!'}), 200  
    else:
            return jsonify({'message': '로그인 실패 ㅠㅠ'}), 404


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=3000, debug=True)

sqlite를 사용해서 DB를 사용해서 user모델을 만들었고 로그인은 /login , 회원가입은 /sign으로 정했다. 

Thunder Client를 통해 post를 해본 결과 잘 입력된 모습이다

 

플러터 - 회원가입 코드
class _JoinAppState extends State<JoinApp> {
  final TextEditingController _usernameController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();
  final TextEditingController _confirmPasswordController =
      TextEditingController();
  final TextEditingController _nameController = TextEditingController();
  late final GlobalKey<FormState> _formKey;
  late final TextEditingController _dateController;
  String? _selectedGender;

  // 회원가입 함수
  Future<void> _signup(BuildContext context) async {
    final String username = _usernameController.text;
    final String password = _passwordController.text;
    final String name = _nameController.text;
    final String date = _dateController.text;
    final String? gender = _selectedGender;

    try {
      final response = await http.post(
        Uri.parse('http://내주소/sign'),
        body: jsonEncode({
          'username': username,
          'password': password,
          'name': name,
          'date': date,
          'gender': gender,
        }),
        headers: {
          'Content-Type': 'application/json',
        },
      );
     
      if (response.statusCode == 201) {
        // 회원가입 성공 시
        showDialog(
          context: context,
          builder: (BuildContext context) {
            return AlertDialog(
              content: const Text('회원가입완료!!'),
              actions: [
                TextButton(
                  onPressed: () async {
                    Navigator.of(context).pop();
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (context) => LoginApp(),
                      ),
                    );
                  },
                  child: const Text('확인'),
                ),
              ],
            );
          },
        );
      } else {
        // 실패 시
        showDialog(
            context: context,
            builder: (BuildContext context) {
              return AlertDialog(
                content: const Text('입력한 정보를 확인해주세요.'),
                actions: [
                  TextButton(
                    onPressed: () {
                      Navigator.of(context).pop();
                    },
                    child: const Text('확인'),
                  ),
                ],
              );
            });
      }
    } catch (e) {
      print('Error sending request: $e');
    }
  }

회원가입 함수인 _signup을 통해 회원가입 성공 시 "회원가입완료"가 적힌 다이얼로그가 뜨고

"확인"을 누르면 로그인 페이지로 넘어가도록 하였다. 

회원가입 정보는 HTTP POST으로 서버로 요청하였고 JSON 형식으로 전달했다.

ElevatedButton(
onPressed: () => _signup(context),

_signup 함수는 버튼을 클릭하면 적용되도록 하였다.

 


플러터 - 로그인 코드 

로그인은 아이디와 비밀번호를 입력하면 로그인이 되고 메인 페이지로 이동하게 하였다.

 // 로그인 함수
  Future<void> _login(BuildContext context) async {
    final String username = _usernameController.text;
    final String password = _passwordController.text;

    try {
      final response = await http.post(
        Uri.parse('http://내주소/login'),
        body: jsonEncode({
          'username': username,
          'password': password,
        }),
        headers: {
          'Content-Type': 'application/json',
        },
      );

      if (response.statusCode == 200) {
        // 로그인 성공 시
        showDialog(
          context: context,
          builder: (BuildContext context) {
            return AlertDialog(
              title: const Text('로그인 성공'),
              content: const Text('로그인하였습니다.'),
              actions: [
                TextButton(
                  onPressed: () {
                    Navigator.of(context).pop(); 
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (context) => const MainpageApp(),
                      ),
                    );
                  },
                  child: const Text('확인'),
                ),
              ],
            );
          },
        );
      } else {
        // 로그인 실패 시
        showDialog(
          context: context,
          builder: (BuildContext context) {
            return AlertDialog(
              title: const Text('로그인 실패'),
              content: const Text('아이디 또는 비밀번호가 일치하지 않습니다.'),
              actions: [
                TextButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  child: const Text('확인'),
                ),
              ],
            );
          },
        );
      }
    } catch (e) {
      // 오류 발생 시
      print('서버에서 오류가 발생했음');
    }
  }

  // 데이터 가져오는 함수
  Future<void> fetchData() async {
    try {
      final response = await http.get(
        Uri.parse('http://내주소/sign'),
      );
      if (response.statusCode == 200) {
        _login;
      } else {
        throw Exception('Failed to load data');
      }
    } catch (error) {
      // 오류 발생 시 처리
      // 예: 오류 메시지 표시
    }
  }

 사실 회원가입과 비슷하지만 달라진 게 있다면 데이터를 가져오는 함수인 fetchData이다!!

먼저 서버로 포스트 요청을 보내고 정보가 맞다면 서버에서 정보를 get 해서 로그인을 한다. 

파이썬 코드에서 User.query.filter_by(username=username , password = password).first()

이 부분이 아이디랑 비번이 맞는지 확인하는 부분이다.