【问题标题】:Laravel RESTful API with Android appLaravel RESTful API 与 Android 应用程序
【发布时间】:2015-06-12 08:51:58
【问题描述】:

我正在使用 Laravel 5 框架开发一个 Android 应用和一个 RESTful API。 我在登录活动中遇到了问题:流程是用户询问第 8 个字符的代码,然后服务器网络向他发送一条短信。然后用户可以使用此代码像密码一样登录。

这是问代码的代码:

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);
}

这是 RESTful API 中生成代码的方法:

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));
}

生成的代码存储在 Laravel 的 Session 中(配置文件驱动)。 当用户想登录时,应用调用这个方法:

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);
}

验证代码的API方法是这样的:

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);
    }
}

我已经使用 Chrome 和 Firefox 测试了 RESTful API,并且登录工作正常。与应用程序没有。事实上问题在于 Session::get('code');在 validateCode 中总是返回一个空值。我检查了使用 Session::put('code', $code); 生成的 Session 文件并且是正确的。但是当调用 Session::get('code') 时,Laravel 会生成另一个 Session 文件,并且似乎没有使用以前的文件。 我在 RESTful API 中禁用了 CSRF 中间件。

怎么了?

【问题讨论】:

  • 在restful中不使用session,添加token并在代码中控制。
  • 我不明白.. 什么时候必须添加令牌?谁生成这个令牌?

标签: android api rest session laravel-5


【解决方案1】:

在服务器端存储会话是没有意义的。 API 假设是无状态的,所以当您完成对代码的第一个请求并将其存储在服务器端的会话中时,会话将结束并且下一个请求将不会记住您设置的任何内容。

如果您想保持代码登录并避免使用令牌,那么您必须从 Android 应用程序发送一个唯一代码来识别用户。然后在服务器端生成代码并将其存储在带有 user_identifier 和 generated_code 的表中,并创建一个模型来访问它,例如

尝试登录

user_id |生成代码


0001 | 87392042

0032 | 83214320

然后将其添加到 saveUser

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

最后在服务器端的 validateCode 中将 $validCode 行替换为以下内容:

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

....

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

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

....

【讨论】:

  • 我是这样做的。非常感谢!
猜你喜欢
  • 2016-11-27
  • 2018-03-04
  • 2011-07-08
  • 2015-09-17
  • 2016-10-22
  • 2012-10-16
  • 2015-01-04
  • 2015-05-09
  • 2019-06-14
相关资源
最近更新 更多