Laravel RESTful API with Android App

I am developing Android app and RESTful API with Laravel 5 Framework. I'm having problems with login activity: the thread is that the user asks for the 8th character code, and the server network sends him an SMS message. The user can then login using this code as a password.

This is the code that asks for the code:

private void askCode(String mobile) {
    GsonRequest<String> jsObjRequest = new GsonRequest<String>(
            Request.Method.GET,
            WebAPIRoute.authGetCode + "/" + mobile,
            String.class, null,
            new Response.Listener<String>() {

                @Override
                public void onResponse(String code) {
                    txtResponse.setText("Code asked successfully.");
                }
            },
            new Response.ErrorListener() {

                @Override
                public void onErrorResponse(VolleyError volleyError) {
                    Toast.makeText(getBaseContext(), volleyError.getMessage(), Toast.LENGTH_SHORT).show();
                }
            });
    this.requestQueue.add(jsObjRequest);
}

      

And this method in RESTful API to generate code:

public function getCode($mobileNum)
{       
    //genero un numero casuale da mandare con l'sms
    $code = mt_rand(10000000, 99999999);

    Session::put('code', $code);

    sendCode($mobileNum, $code); //send code by SMS

    return response()->json(array("success"=>true));
}

      

The generated code is saved in the Laravel session (with a file driver). When the user wants to login, the application will call this method:

private void saveUser(final String code, final String mobile, final String name) {
    HashMap<String, String> params = new HashMap<String, String>();

    params.put("nickname", name);
    params.put("mobile", mobile);
    params.put("code", code);

    GsonRequest<String> jsObjRequest = new GsonRequest<String>(
            Request.Method.POST,
            WebAPIRoute.authValidateCode,
            String.class,
            params,
            new Response.Listener<String>() {
                @Override
                public void onResponse(String authtoken) {
                    final Account account = new Account(accountName, mAccountType);

                    String authtokenType = mAuthTokenType;
                    // Creating the account on the device and setting the auth token we got
                    // (Not setting the auth token will cause another call to the server to authenticate the user)
                    mAccountManager.addAccountExplicitly(account, code, null);
                    mAccountManager.setAuthToken(account, authtokenType, authtoken);

                    Bundle data = new Bundle();
                    data.putString(AccountManager.KEY_ACCOUNT_NAME, accountName);
                    data.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
                    data.putString(AccountManager.KEY_AUTHTOKEN, authtoken);
                    data.putString(PARAM_USER_PASS, code);
                    data.putBoolean(ARG_IS_ADDING_NEW_ACCOUNT, true);

                    final Intent res = new Intent();
                    res.putExtras(data);

                    setAccountAuthenticatorResult(res.getExtras());

                    Intent i = new Intent(getBaseContext(), MyEventsActivity.class);
                    startActivity(i);
                }
            }
            ,
            new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError volleyError) {
                    Log.e(TAG, volleyError.getMessage(), volleyError);
                    showMessage("Errore nell'autenticazione. Riprova piu` tardi.");
                }
            });

    requestQueue.add(jsObjRequest);
}

      

The API method that the code validates is:

public function validateCode() {
    $code = trim(Input::get('code'));
    $nickName = trim(Input::get('nickname'));
    $phoneNum = trim(Input::get('mobile'));

    if (empty($phoneNum))
        abort(400, 'mobile parameters not provided.');

    if (empty($code))
        abort(400, 'code parameters not provided.');

    if (empty($nickName))
        abort(400, 'nickname parameters not provided.');

    $validCode = Session::get('code');
    Log::info('code: ' . $code . " validCode: " . $validCode);

    if($code == $validCode) {
        Session::forget('code');

        // Retrieve the user by the attributes, or instantiate a new instance...
        $user = User::firstOrCreate(['Mobile' => $phoneNum]);

        //aggiorno i campi nickname e password col nuovo codice
        $user->Nickname = $nickName;
        $user->password = $code;

        //save!
        $user->save();

        //viene usata l'autenticazione di Laravel e gli serve una password
        $token = JWTAuth::attempt(['Mobile' => $phoneNum, 'password' => $code]);

        return response()->json($token);
    } else {
        //return response()->json(array('success' => false, 'error' => 'The code isn\'t correct.'));
        abort(401, 'The code isn\'t correct.' . $validCode);
    }
}

      

I have tested RESTful APIs with Chrome and Firefox and login works. With attachment no. Infact the problem is that Session :: get ('code'); in validateCode always returns blank. I checked the session file generated with Session :: put ('code', $ code); and is correct. But when Session :: get ('code') is called, Laravel generates another session file and doesn't seem to use the previous one. I disabled CSRF middleware in RESTful API.

What's wrong?

+3


source to share


1 answer


Saving the session on the server side is pointless. The API is supposed to be stateless, so in the second case, you complete the first request for the code and store it in a server side session, the session ends and the next request won't remember anything you set.

If you want to keep the login code and not use tokens, you will have to send a unique code from the Android app that identifies the user. Then create server side code and store it in a table with user_identifier and generated_code and create a model to access it eg.

AttemptedLogin

user_id | generatedCode


0001 | 87392042



0032 | 83214320

Then add this for saveUser

params.put("user_id", user_id); // can be the android device ID or even a unique timestamp

      

Finally, on the server side, in validateCode, replace the $ validCode line with the following:

$user_id = trim(Input::get('user_id')); 

....

$validCode = AttemptedLogin::where('user_id', $user_id)->first();

if($code == $validCode->generatedCode) {
    $validCode->delete();

....

      

+3


source







All Articles