skip to Main Content

I am currently working on a flutter application using dart language. I am trying to use AstraDB for my login page authentication of users’ email and password using the http flutter package.

The following are the code I used for creating the the data in AstraDB as well as for the application, for the api urls I have followed the same format as indicated with my respective values and "users" is the name of my table in AstraDB.

CQL command used to create the table in AstraDB Console:

CREATE TABLE IF NOT EXISTS users (
  email text PRIMARY KEY,
  password text
);

CQL command used to insert data in AstraDB Console:

INSERT INTO users (email, password) VALUES ('[email protected]', 'password123');

Dart code for the application’s login page in Android Studio:

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'AstraDB HTTP Demo',
      home: LoginPage(),
    );
  }
}

class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  Future<void> _login() async {
    final response = await http.post(
      Uri.parse('https://YOUR-ASTRA-DB-ID-YOUR-ASTRA-DB-REGION.apps.astra.datastax.com/api/rest/v2/keyspaces/keyspace_name/users?apiToken=YOUR-APPLICATION-TOKEN'),
      headers: <String, String>{
        'Content-Type': 'application/json; charset=UTF-8',
      },
      body: jsonEncode(<String, String>{
        'email': _emailController.text,
        'password': _passwordController.text,
      }),
    );

     if (response.statusCode == 200) {
      print('Login Successful');
      // TODO: Handle successful login.
    } else {
      throw Exception('Failed to log in.');
    }
  }

  Future<void> _signup() async {
    final response = await http.post(
      Uri.parse('https://YOUR-ASTRA-DB-ID-YOUR-ASTRA-DB-REGION.apps.astra.datastax.com/api/rest/v1/signup'),
      headers: <String, String>{
        'Content-Type': 'application/json; charset=UTF-8',
      },
      body: jsonEncode(<String, String>{
        'email': _emailController.text,
        'password': _passwordController.text,
      }),
    );

    if (response.statusCode == 200) {
      print('Signup Successful');
      // TODO: Handle successful signup.
    } else {
      throw Exception('Failed to sign up.');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('AstraDB HTTP Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            SizedBox(
              width: 300,
              child: TextField(
                controller: _emailController,
                decoration: InputDecoration(
                  border: OutlineInputBorder(),
                  labelText: 'Email',
                ),
              ),
            ),
            SizedBox(height: 30),
            SizedBox(
              width: 300,
              child: TextField(
                controller: _passwordController,
                obscureText: true,
                decoration: InputDecoration(
                  border: OutlineInputBorder(),
                  labelText: 'Password',
                ),
              ),
            ),
            SizedBox(height: 30),
            ElevatedButton(
              onPressed: _login,
              child: Text('Login'),
            ),
            SizedBox(height: 15),
            ElevatedButton(
              onPressed: _signup,
              child: Text('Sign Up'),
            ),
          ],
        ),
      ),
    );
  }
}

Firstly, when trying running the application on my tablet and typing in the respective values in the login fields, it provides me with the following message in Android Studios’ terminal.

E/flutter (28320): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Exception: Failed to log in.
E/flutter (28320): #0      _LoginPageState._login (package:sign_in/main.dart:42:7)
E/flutter (28320): <asynchronous suspension>

Secondly, I tried checking if the ApiURL was correct using my web browser (Google Chrome) and it provided this error on the page. I am not sure if this is the correct way to check.

{"description":"where parameter is required","code":400}

I expected the application’s login to be successful upon filling in the appropriate details, allowing the user to proceed to use the rest of the application features. I initially wanted to add a sign up feature as well but my login itself does not work itself. However, this was not the case and I have been trying to find a solution for this for approximately two weeks now. All help is appreciated. Thank you.

2

Answers


  1. You want to access the data in table users. There a couple of things to update.

    Table Design

    To authenticate user we want to execute the query select email,password from users as such both email and password should be part of the key. The table should be changed to:

    CREATE TABLE IF NOT EXISTS users (
     email text,
     password text,
     PRIMARY KEY((email), password)
    );
    

    In the table make sure you do not store the password in clear text but rather encode it in SHA1 for security reason.

    The Query

    • To use HTTP API, You will need an authentication key to be passed in the header. (this is the cause of your error above). To create one follow the instructions

    • If you look at the Swagger UI available in Astra UI your are targeting this resource

    [GET] /v2/keyspaces/{keyspaceName}/{tableName}
    
    • The where clause you need is
    where={ 'email': {'$eq': '[email protected]'},  'password': {'$eq': 'password123'}}
    
    • But as it is a GET request the parameter needs to be encoded and the full request looks like:
    curl -s -L -X GET 'https://${ASTRA_DB_ID}-${ASTRA_DB_REGION}.apps.astra.datastax.com/api/rest/v2/keyspaces/demo/users?where=%7B%20%22email%22%3A%20%7B%22%24eq%22%3A%20%22john%40example.com%22%7D%20%2C%20%22password%22%3A%20%7B%22%24eq%22%3A%20%22password123%22%7D%20%7D' 
    -H "X-Cassandra-Token:${ASTRA_TOKEN}" 
    -H "Content-Type: application/json" 
    -H "Accept: application/json"
    

    The output look like:

    {"count":1,"data":[{"email":"[email protected]","password":"password123"}]}
    

    I propose you to use the field to tell if authentication is successful or not.

    Login or Signup to reply.
  2. You need to pass the authentication token in the header section. In your app, you have incorrectly included the token in the URI which is incorrect.

    To illustrate, here are the contents of my users table:

     email          | password
    ----------------+------------
     [email protected] | Wonder7and
    

    WARNING: I stored the password in plain text for simplicity but this is not recommended. Best practice is to hash-encode the password before saving it.

    The API endpoint I use to query is (note the @ symbol in the email address is HTTP-encoded):

    /api/rest/v2/keyspaces/community/users/alice%40mail.com
    

    The headers are:

    Content-Type: application/json
    X-Cassandra-Token: abCdeFG...uVWx0z
    

    This will return the following response:

    {
      "count": 1,
      "data": [
        {
          "email": "[email protected]",
          "password": "Wonder7and"
        }
      ]
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search