flutter авторизация в приложении

Flutter. Часть 2. Пишем первый экран

Содержание

В предыдущей статье мы подключили Flutter SDK и создали hello world приложение. Сейчас создадим простое приложение где реализуем экран авторизации, простой механизм валидации логина и пароля и если валидация пройдёт успешно, то осуществить переход на следующий экран:

animation flutter

Создадим новый проект как было описано в предыдущей статье. Заменим содержимое файл \lib\main.dart на представленный ниже код:

Если запустить этот код, то на экране будет отображён пустой белый экран с пометкой debug в правом верхнем углу:

0.21pttad99gf

Теперь разместим визуальные компоненты на экране. Как мы помним из первой стать во flutter все визуальные компоненты являются виджетами. Благодаря взаимовложенности виджетов друг в друга и строиться графический интерфейс.

Сейчас у нас есть пустой экран, создадим два поля для ввода текста и кнопку login.

Для того что бы выронить все элементы по центру экрана воспользуемся классом Center (строка 9). Для расположения все элементы в один столбец необходимо использовать класс Column в котором для выравнивания дочерних элементов по центру задаём значение параметра mainAxisAlignment: MainAxisAlignment.center (строки 10-11).

В класс Column можно передать массив виджетов которые будут отображаться внутри него в вертикальном порядке друг под другом (строка 12). Каждое полу ввода нужно ограничить по ширине, поэтому необходимо “завернуть” всё это в ещё один класс Container. У которого уже можно задать нужный параметр width (строка 19). В качестве параметров стиля для текста создадим две переменные _sizeTextBlack и _sizeTextWhite (строки 2-3).

Для поля ввода Email зададим параметр типа клавиатуры TextInputType.emailAddress, а для поля пароля выставим obscureText в true (строка 16 и 24).

Для отображение кнопки нам понадобиться отступ который мы сможем задать через класс Padding (строка 30).

В итоге у нас получиться следующий результат:

0.kpqyaj9z6j

Далее реализуем простую логику валидации почты и пароля. Для хранения и передачи данных создадим в классе MyApp две переменные _email и _password:

У виджета TextFormField есть метод onSaved который возвращает значение поля ввода при изменениях. Это значение сохраняем в переменные _email и _password соответственно. Так же есть функция validator в которой можно реализовать логику отображения подсказки в случае если валидация не пройдена.

Обработаем событие нажатие на кнопку. В виджет MaterialButton есть функция onPressed который вызывается после нажатие кнопки. Для лаконичности кода вынесем обработку нажатия в отдельный метод submit.

Для того что бы провалидировать сразу все поля нужно создать дополнительный виджет Form. У него есть тип key, который создаёт контейнер для полей формы. Его будем хранить в поле formKey.

Реализуем метод submit(). В нём выполняется получение полей ввода и вызова метода validate():

После успешной валидации скрываем клавиатуру и открываем экран в который передадим значение логина и пароля:

0.yfwksc1ktbs

Весь код проекта можно посмотреть по ссылке.

Источник

How to authenticate and login users in Flutter from a REST Api

Suggested laptop for programming
61PXjYVtmqL. SL1407 Lenovo IdeaPad S145 AMD Ryzen 5 15.6″ FHD Thin and Light Laptop (8GB/512GB SSD/Windows10/Office/Platinum Grey/1.85Kg)

Introduction

In this article we will discuss how to use a REST api backend to authenticate users from a Flutter app. We will build a very basic nodejs REST api backend. If you already have a backend then you can use that also. And then we will be building a basic Flutter app to connect to this backend and login to the app. It is assumed that the reader has a basic understanding of nodejs, rest api principles and flutter.

Overview of the app

The flowchart below shows the flow of this app.

flutter restapi

And here is a short clip of the app in action.

flutter restapi reduceds

Building the REST api backend

We will be using nodejs to build this backend. Lets begin.

Once these are installed, we write our api. Here is the code.

Save it as index.js and to run this, do node index.js at the terminal.

We are exposing two endpoints:

\user\login is a POST endpoint accepting a json input of username and password of the following format:

As this is just a demonstration api, we are simply checking if the username and password are same and if they are we are returning a mock user object in json format. If the username and password are not same, we respond back with a Authentication failed message.

\user\:userId returns the user data of the userId passed in the parameter. For demonstration purpose, we simply return a mocked user json object.

Building the Flutter app

This app will consist of only two screens, the login screen and the home screen. But before we dive into the screens lets discuss how we can consume the api from flutter.

Interfacing with the REST api

Authentication

For authentication we will be doing POST \user\login passing the username and password as JSON in the following format.

Here is the flutter method for it:

If you are trying this in your own machine then your baseUrl might be different. Check your ip address and change the baseUrl accordingly.

A future (lower case “f”) is an instance of the Future (capitalized “F”) class. A future represents the result of an asynchronous operation, and can have two states: uncompleted or completed.

The http.post method calls the REST api POST endpoint /user/login and passes the following json body.

The api will respond back with a response code of 200 when the auth is successful and a json will be sent back:

ApiResponse class encapsulates the response from the api. Here is how the class looks:

This is how we are using this class in our authenticateUser method:

Let’s now take a look at the User class, this class is built based on the response that we are getting from our REST api.

We have also enclosed our code in a try catch block to catch any exceptions like uncreachable server or other errors and populate the ApiError class.

Getting user details from the api

Building the UI

Login screen

Our login screen will have two fields to enter the username and password along with a button. Here is the snippet of the code that builds the UI.

Here is the _handleSubmitted method:

To use authenticateUser method we have to import the following packages:

Once the user is successfully authenticated we load up the home screen and we do not want that the user should be able to come back to the login screen. To achieve this we use the Navigator.pushNamedAndRemoveUntil method. The documentation says:

Push the route with the given name onto the navigator that most tightly encloses the given context, and then remove all the previous routes until the predicate returns true.

Home Screen

We show the user’s name, last login date time and the email address. We do this by extracting the User object from the navigator’s argument.

The logout button simple removes the userId that we had saved in the login screen from the SharedPreferences.

Wrapping up

We have now seen both the login screen and the home screen. We will now look at the rest of the code of the app and how these screens are called. The file structure of the app is:

The main.dart file is the starting point of this app. We have the main() method in this file.

The Landing class in landing.dart file checks if the user has already logged in and if finds this to be true, loads the home screen else loads the login screen.

If we find userId in the SharedPreferences then we call the getUserDetails() method to fetch the details from our rest api. We then show the home screen.

In case userId is not found, we show the login screen.

Hope this is of help. Please mail us in case of any questions.

Источник

User Authentication + JWT Authorization With Flutter and Node

Cover Photo by James Sutton on Unsplash

The series of posts about advanced networking topics applied to Flutter apps continues. As always, this is meant for people who already have a good understanding of Flutter and know how to use Flutter widgets and the basics of the http library.

That’s the kind of stuff you can learn by reading my Flutter book.

You can learn about them online too, if you hate books. I won’t be judging you.

What We’re Going to Build

The app we’re going to build is the simplest example of an app that requires authentication: it allows anyone to sign up, and any logged in user can access a piece of data. We’re going to implement the back-end with Node and the front-end with Flutter.

What is JWT

JWT (JSON Web Token) is a standard that specifies a very secure way to transmit session tokens between an user-accessible front-end (that we’ll write using Flutter) and a back-end (that we’ll write using Node).

Unlike a more traditional user session implementations, in which the session token is stored both on the server and on the client, the client sends the token along with every request and the server can check whether a session exists with that token for that user and decide whether to grant access based on that and what the user is actually allowed to do.

JWT is different. The server doesn’t store the token: at the time of authentication, it sends a signed token, but it doesn’t store it, instead relying on the signature it attaches to the token (obtained either with RSA, ECDSA or HMAC with SHA256 usually), which allows it to verify both the authenticity of the token and whether it was tampered with.

This means the token’s payload can contain both data the front-end needs, since it can be freely accessed by it, and data (like the user name/ID and/or an expiration date) the server needs to validate the request and the token.

Analyzing an Example

If you pay attention, you’ll notice there are two dots. The first ( eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 ) can be decoded to ASCII to <"alg":"HS256","typ":"JWT">, which is a JSON object, which can be formatted like this:

The second string ( eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwiaWF0IjoxNTgxOTY2MzkxLCJleHAiOjE1ODMyNjIzOTF9 ) can be decoded and formatted to:

The third string is just the signature obtained as an HMAC with SHA256.

Our API Interface

Our backend is going to have three routes:

Implementing the Front-End App with Flutter

You can find the code for this Flutter app on GitHub by clicking here.

Using The flutter_secure_storage Package

The flutter_secure_storage package is very easy to use: it’s simply key-value pair storage, but using iOS’s Keychain directly or by encrypting the data, storing the encrypted data in Android’s Shared Preferences.

You can write the myvalue and associate it to the mykey key using it by using storage.write() in the following way:

storage.write is asynchronous (it has a return type of Future ), so you should use await if you need to pause execution while it executes.

You can use storage.delete() to delete a value (it’s also asynchronous):

Two methods exist, called readAll() and deleteAll() (both asynchronous), which respectively return a Map of all the stored values and delete all of the stored values.

Implementation

The Flutter app doesn’t need to be particularly complicated to be able to work with JWT: it’s mostly about writing an authentication flow, storing the JWT token and sending it with each request.

In addition to that, for this example we’ll check whether the token has expired on the front-end and we’ll show the username after the user logs in, so we’ll actually have to decode the payload.
We are going to store the JWT using the flutter_secure_storage package, which is the simplest way to access the secure storage interfaces provided by iOS and Android from a Flutter app.

Here are two screenshots of what we want to achieve:

Screenshot 1581601687

Screenshot 1581601694

Add the flutter_secure_storage and http packages to the app’s dependencies in pubspec.yaml :

Then, set the minimum supported Android version to SDK level 18 (Android 4.3) because that’s required by flutter_secure_storage.

The Structure of Our Flutter App

The structure of our Flutter app is going to be the following:

Creating a Log-In Page

That’s a bit boring to worry about now, let’s build some UI and create a log-in page!

The log-in page itself will be a StatelessWidget called LoginPage :

The nature of the login page and our implementation means we are going to make extensive use of dialogs. This means we’ll create a helper method in order to make everything more succint:

We’ll also create methods that attempt to login and signup the user, and they’re very simple POST requests, as we saw earlier on when we talked about our app’s API interface.

We’ll return a string for the login method, which will be null in case of an error (i.e. wrong username/password) and the JWT if the authentication process succeded:

The sign-up method doesn’t actually have to return anything useful to the app, so we can just return the status code and deal with that later to establish whether the operation was successuful or not:

Here comes the fun part!

what’s the body going to be? A Column with two TextFields that allow the user to insert username and password and two FlatButton s: one to log in and one to sign up. We’ll also add some padding around it given that it looks horrible to my eyes without it:

The labelText in the InputDecoration is the nicest looking way to tell users what each TextField is for.

Define the _usernameController and _passwordController TextEditingController s somewhere in the class definition, like this:

The function that handles sign-up is going to be complicated by the checking of a few conditions.

We are going to check on the front-end that the user doesn’t try to use un username or password less than 4 characters long. This should also be done on the back-end, but this tutorial focuses more on Flutter than it does on Node, so we’re just going to do this on the front-end.

If those two inputs are valid, we are going to attempt to sign up, and check the response. If we get HTTP status code 201, it means the user was created and we can simply tell the user to log in with those credentials.

If we get HTTP status code 409, it means the username is already in use, and we can tell that to the user. If the response’s status code is neither 409 nor 201, the request failed (probably because of a network error or an internal server error), we just tell the user an unknown error occurred:

The entire LoginPage definition looks like this in the end:

Creating an Home Page

The HomePage’s build() method

The HomePage widget itself is going to be made of a FutureBuilder that waits for the GET request to the server to get the data, and then either displays it or some text informing the user an error has occurred, if that is the case:

The HomePage class definition is, therefore, the following:

Creating the MyApp Class

The MyApp class is the class that gets run when the app starts. It needs to check whether it already has a JWT and, if it has one, it should check whether it is valid, whether it has expired and, based on that, decide whether to ask the user to log in or whether to show them the home page. We are going to need to create a method called jwtOrEmpty()

That’s because the FutureBuilder ‘s snapshot.hasData parameter that gets passed to the builder function would return false if it were to receive a null value, which would be the case if the JWT were non-existent. This is unwanted because we would have no way of distinguishing the case in which we are still waiting for the Future to return and the case in which there is no JWT. Having this second case return an empty string instead of null fixes the issue.

All that’s left to do is to create a build() method, which should return a MaterialApp (that’s the whole point of the MyApp class) that, after getting the JWT and checking it, either shows the user the login page or the home page based on the criteria I described earlier.

All of that ends up in the following class definition:

Implementing the Back-End with Node

You can find the code for this Node backend on GitHub by clicking here.

The Node back-end is where most of it happens: we need to create rules for login, logout and some sort of data to access. We are going to store users in an SQLite database to keep things simple for this example.

Choosing How to Sign the Token

The token can be signed using either a method based on public key cryptography (for example using RSA or ECDSA) or by relying on hashing the concatenation of the secret key and the message (called a payload in JWT terms) with any hashing algorithm (usually sha256). The latter concept has been expanded into a full standard for generation of a digital signature (called HMAC) that is protected against collisions and length extension attacks, about which you can find more information on Wikipedia.

For this example, that’s what we will use: HMAC with SHA256. That’s because it’s easier for a quick example for a blog post because we have greater freedom with our choice of private key. When building a real app, you should obviously consider the advantages and disadvantages of this approach based on your needs and the requirements your apps needs to meet. For this post we’ll use a short and simple string as a key, that’s not how it’s supposed to be done: it should ideally be a generated pseudorandom (and particularly long) key, just like any RSA or ECDSA key generated with OpenSSL, otherwise you’re making it very easy for attackers to crack your private key and generate their own JWT tokens your back-end will think are genuine, allowing them to pretend they’re logged in as any user, completely breaking your website’s security.

Safety First!

In other words, this is an example meant to be as easy to follow as possible and you must take the appropriate precautions when it comes to choosing or generating a private key. Since we’re talking about security precautions, you should obviously use TLS for communications between front-end and back-end in production. Also, salt the passwords before hashing them if you really want to play it safe.

Building the Back-End

These are the libraries we are going to use:

Using the jsonwebtoken Library

The jsonwebtoken NPM package is very, very easy to use. It provides us with three functions, once imported with jwt = require(«jsonwebtoken») :

For example, if your payload is and the private key is stored in the variable privKey and you want to create a JWT using the provided RSA private key that is valid for two hours, you can run

and then, if pubKey is the corresponding RSA public key, you can run

In our example we are going to use just one secret key (stored in a variable called KEY ), so we are going to generate the JWT as an HMAC with SHA256 (HS256) and have it expire after 15 days, which means we are going to generate the JWT with:

I recommend you look at the documentation for the package on the NPM page for a more complete list of options. I’m not writing an API reference here, I’m trying to make you understand how to implement this.

A Quick Introduction to the sqlite3 Node SQLite Driver

The sqlite3 Node SQLite Driver doesn’t come with too many bells and whistles. There are other packages that provide different interfaces, this is the most basic one and it’s perfect for a very basic and simple example that really shouldn’t require a huge node_modules directory or particularly complicated.

The functions we are going to use are:

Two other functions exist called db.all() and db.each() which respectively pass all of the rows as an array to the callback and call the callback for each row returned, only passing one at a time. We would need to use such functions if we wanted, for example, to check whether a log-in attempt failed because the password was wrong, even though the given username exists in the database.

Query Parameters

Installing Dependencies

As always, create a Node project with

and install the packages I listed above with

Initial Config

We are going to import all of the libraries into our code and set the secret key (a very unsafe one, but this is just an example) and initialize the database connection:

Initializing the Database

You can do this either directly using the SQLite or any other tool of your choice or by creating this Node.js file and running it:

Implementing Sign-Up

Signing users up is simple and has nothing to do with how we manage authorization: we’re not logging them in, which means we just need to check whether they have already signed up. If they haven’t, we sign them up by adding them to our database. We are going to use the Express built-in urlencoded middleware to parse the body of the request and we’re going to log everything to the server console:

Logging in is all about looking in the database for the user who is trying to log in, generating a JWT and returning it if we find it, and returning an error if we don’t:

Verifying the token is very easy with the Node library we are using, meaning the /data route is written very quickly and painlessly, remembering that a failure in verifying the JWT will result in an error being thrown:

As usual, we take the port to run the server on from the environment variable PORT and, if that fails, we set it to 3000 and run the server:

Источник

Пример клиент-серверного приложения на Flutter

image loader

В этом туториале мы собираемся разработать приложение, которое получает данные через интернет и отобразим их списком. Примерно вот так

image loader

Окей, начнем с создания проекта. Пропишем в командной строке следующее

Далее идем в наш файл зависимостей pubspec.yaml и добавляем нужные нам

После этого устанавливаем эти зависимости следующей командой

Для этого приложения мы будем использовать jsonplaceholder для получения моковых данных. Если вы не знакомы с этим сервисом, это онлайн REST API сервис, который может отдавать фейковые данные. Это очень полезно для построения прототипов приложения.

Открыв следующую ссылку jsonplaceholder.typicode.com/posts?_start=0&_limit=2 вы увидите JSON ответ, с которым мы будем работать.

Заметьте, в нашем GET запросе мы указали начальное и конечное ограничение в качестве параметра.

Отлично, теперь мы знаем как будут выглядеть структура наших данные! Давайте создадим модель для них.

Создадим файл post.dart со следующим содержанием

Post это только класс с id, title и body. Мы так же можем переопределить функцию toString для отображения удобной строки позднее. В дополнении мы расширяем класс Equatable, таким образом мы можем сравнивать объекты Posts.

Теперь у нас есть модель ответа от сервера, давайте реализовывать бизнес логику (Business Logic Component (bloc)).

Перед тем как мы окунемся в разработку приложения, необходимо определить что наш PostBloc будет делать.

На верхнем уровне, он будет отвечать за обработку действий юзера (скроллинг) и получение новых постов, когда слой презентации запросит их. Давайте начнем реализовывать это.

Наш PostBloc будет отвечать только на один event. Получение данных, которое будет показывать на экране по мере необходимости. Создадим класс post_event.dart и имплементируем наше событие

Снова переопределим toString для более легкого чтения строки отображающего наш ивент. Так же нам необходимо расширить класс Equatable для сравнения объектов.

Резюмируя, наш PostBloc будет получать PostEvents и конвертировать их в PostStates. Мы разработали все ивенты PostEvents (Fetch), перейдем к PostState.

Наш презентационный слой должен иметь несколько состояний для корректного отображения.

isInitializing — сообщит презентационному слою, что необходимо отобразить индикатор загрузки, пока данные грузятся.

posts — отобразит список объектов Post

isError — сообщит слою, что при загрузке данных произошла ошибок

hasReachedMax — индикация достижения последней доступной записи

Создадим класс post_state.dart со следующим содержанием

Мы использовали паттерн Factory для удобства и читабельности. Вместо ручного создания сущностей PostState мы можем использовать различные фабрики, например PostState.initial()

Теперь у нас есть ивенты и состояния, пора создать наш PostBloc
Для упрощения наш PostBloc будет иметь прямую зависимость http client, однако в продакшене вам бы следовало завернуть ее во внешнюю зависимость в api client и использовать Repository паттерн.

Заметьте, что только из объявления нашего класса можно сказать, что он будет принимать на вход PostEvents и отдавать PostStates

Перейдем к разработке initialState

Далее необходимо реализовать mapEventToState, который будет срабатывать каждый раз при отправке события.

Теперь каждый раз PostEvent отправляется, если это событие выборки и мы не достигли конца списка будет отображено следующие 20 записей.

Немного доработаем наш PostBloc

Отлично, мы завершили реализацию бизнес логики!

Создадим класс main.dart и реализуем в нем runApp для отрисовки нашего UI

Далее создадим HomePage, который отобразит наши посты и подключится к PostBloc

Далее реализуем BottomLoader, который будет показывать пользователю загрузку новых постов.

И наконец, реализуем PostWidget, который будет отрисовывать один объект типа Post

На этом все, сейчас вы можете запустить приложение и посмотреть результат

Источник

Понравилась статья? Поделить с друзьями:
Добавить комментарий
  • Как сделать успешный бизнес на ритуальных услугах
  • Выездной кейтеринг в России
  • Риски бизнеса: без чего не обойтись на пути к успеху
  • fluapp что за приложение
  • fls0175 облицовка боковая правая