【问题标题】:PassportJS req.user undefined when authentification from an android app来自Android应用程序的身份验证时未定义Passport JS req.user
【发布时间】:2015-01-07 19:38:23
【问题描述】:

我正在 nodeJS 中开发一个 API,我正在使用 PassportJS 进行身份验证部分。 我正在使用这个很好的教程:http://scotch.io/tutorials/javascript/easy-node-authentication-setup-and-local

在浏览器中,我可以获取用户,但是当我尝试使用 android 应用程序时,req.user 未定义。

app.post('/login', passport.authenticate('local-login', {
    successRedirect: '/loginSuccess',
    failureRedirect: '/loginFailure',
    failureFlash : true // allow flash messages
}));

app.get('/loginFailure', function(req, res, next) {
    res.setHeader('Content-Type', 'application/json');
    res.json({user: req.user, message: req.flash('loginMessage')[0]});
});

app.get('/loginSuccess', function(req, res, next) {
    console.log(req.user);
    res.setHeader('Content-Type', 'application/json');
    res.json({user: req.user, message: "test"});
});

//

passport.use('local-login', new LocalStrategy({
    usernameField : 'login',
    passwordField : 'password',
    passReqToCallback : true // allows us to pass in the req from our route (lets us check if a user is logged in or not)
},
function(req, login, password, done) {
    // asynchronous
    process.nextTick(function() {
        User.findOne({$or:[{'local.email': login.toLowerCase()}, {'local.login': login}]}, function(err, user) {
            // if there are any errors, return the error
            if (err)
                return done(err);

            // if no user is found, return the message
            if (!user)
                return done(null, false, req.flash('loginMessage', 'No user found.'));

            if (!user.validPassword(password))
                return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));

            // all is well, return user
            else
                return done(null, user);
        });
    });

}));

还有我的安卓代码:

public class LoginActivity extends Activity {

      private Button loginButton = null;
      private Button cancelButton = null;


      private boolean isOnline() {
            ConnectivityManager cm =
                (ConnectivityManager) getSystemService(AppInfo.getAppContext().CONNECTIVITY_SERVICE);
            NetworkInfo netInfo = cm.getActiveNetworkInfo();
            if (netInfo != null && netInfo.isConnectedOrConnecting()) {
                return true;
            }
            return false;
        }

      private OnClickListener clickListenerLoginButton = new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!isOnline()) {
                    Toast.makeText(LoginActivity.this, getResources().getString(R.string.ERROR_NO_NETWORK), Toast.LENGTH_LONG).show();
                    return ;
                }
                new LoginOperation().execute(getResources().getString(R.string.urlLogin));
            }
        };

        private OnClickListener clickListenerCancelButton = new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent result = new Intent();
                setResult(RESULT_CANCELED, result);
                finish();
            }
        };

      @Override
      public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        loginButton = (Button)findViewById(R.id.loginButton);
        cancelButton = (Button)findViewById(R.id.cancelButton);

        loginButton.setOnClickListener(clickListenerLoginButton);
        cancelButton.setOnClickListener(clickListenerCancelButton);
      }

      private Object user;

      private class LoginOperation  extends AsyncTask<String, Void, Void> {

        String Response = "";
        String Error = null;
        String data ="";
        private ProgressDialog Dialog = new ProgressDialog(LoginActivity.this);
        EditText login_emailEditText = (EditText) findViewById(R.id.login_emailEditText);
        EditText passwordEditText = (EditText) findViewById(R.id.passwordEditText);

        protected void onPreExecute() {

            Dialog.setMessage("Please wait..");
            Dialog.show();

            try{
                data += "&"+URLEncoder.encode("login", "UTF-8")+ "=" +URLEncoder.encode(login_emailEditText.getText().toString(), "UTF-8");
                data += "&"+URLEncoder.encode("password", "UTF-8")+ "=" +URLEncoder.encode(passwordEditText.getText().toString(), "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

        }

        @Override
        protected Void doInBackground(String... urls) {
            BufferedReader reader=null;
                try
                {
                   URL url = new URL(urls[0]);
                  // Send POST data request
                  URLConnection conn = url.openConnection();
                  conn.setDoOutput(true);
                  OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
                  wr.write( data );
                  wr.flush();

                  // Get the server response
                  reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                  StringBuilder sb = new StringBuilder();
                  String line = null;

                    // Read Server Response
                    while((line = reader.readLine()) != null) {
                        sb.append(line + " ");
                    }

                    // Append Server Response To Content String
                   Response = sb.toString();
                }
                catch(Exception ex) {
                    Error = ex.getMessage();
                }
                finally {
                    try {
                        reader.close();
                    }
                    catch(Exception ex) {}
                }
            return null;
        }

        protected void onPostExecute(Void unused) {
            Dialog.dismiss();

            if (Error != null) {
                Toast.makeText(LoginActivity.this, "ErrorAndroid: " + Error, Toast.LENGTH_LONG).show();
            } else {
                try {
                    JSONObject jsonObject = new JSONObject(Response);
                    Toast.makeText(LoginActivity.this, jsonObject.toString(), Toast.LENGTH_LONG).show();
                    user = jsonObject.get("user");
                } catch (JSONException e) {
                    Toast.makeText(LoginActivity.this, "ErrorAndroidJSON: " + e.getMessage(), Toast.LENGTH_LONG).show();
                }

             }
        }

      }
}

使用浏览器试试: 用户1/密码1

http://exemple.com:4040/login

我正在使用 express4.0,但我也尝试使用 express3.8。 我完全迷失了,我完全不明白为什么它可以在浏览器上工作,但不能在应用程序上工作。

编辑:我认为问题出在我在android中调用API的方式上,http头请求应该与浏览器不同,所以它不能正常工作。

感谢您的帮助。

【问题讨论】:

  • 你是说护照js(不是密码js)
  • 是的,对不起,我编辑了我的帖子
  • 当您说“在浏览器中,我可以获取用户,但是当我尝试使用 android 应用程序时,req.user 未定义。” - 你是什么意思?你要去哪个网址?
  • 也可能会更好地发布一些您的android应用程序代码,即调用网址等......
  • 使用浏览器,当我在我的 android 应用程序上发布请求时,我只收到 {message: "test"} 并且我的节点服务器告诉我 req.user 未定义

标签: android node.js express passport.js passport-local


【解决方案1】:

你 expressjs 服务器正在返回 "302 Moved Temporarily"

    HTTP/1.1 302 Moved Temporarily
    X-Powered-By: Express
    Access-Control-Allow-Origin: *
    Access-Control-Allow-Headers: Content-Type
    Access-Control-Allow-Credentials: true
    Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS
    Location: /loginSuccess
    Vary: Accept
    Content-Type: text/html; charset=UTF-8
    Content-Length: 82
    Date: Wed, 08 Oct 2014 23:29:31 GMT
    Connection: keep-alive

"Location" 设置为/loginSuccess

Android URLConnection 默认自动跟随重定向,并且正在获取/loginSuccess返回的数据

问题是,你的 expressjs 服务器要求你发回它设置的 cookie;

所以解决办法是

  • 禁用自动重定向;在初始url.openConnection()之后添加以下行

    ((HttpURLConnection)conn).setInstanceFollowRedirects(false);
    
  • 手动跟随 url 重定向,在 GET 请求中设置 cookie 值。在wr.flush(); 行后添加以下代码sn-p

    String cookie = conn.getHeaderField("Set-Cookie");
    conn = new URL("http://example.com:4040/loginSuccess").openConnection();
    conn.setRequestProperty("Cookie", cookie);
    conn.connect();
    
  • 考虑将上面的硬编码网址替换为"baseUrl + conn.getHeaderField("Location")"

【讨论】:

  • 我做了 2 处修改,现在我在 loginSuccess 的 req 中有用户。但是当我想访问一个检查用户是否登录的路由之后(它正是函数 ligne 66:github.com/scotch-io/easy-node-authentication/blob/local/app/…),API 告诉我用户没有登录。那是因为我必须把获取请求中的cookie?如果是,有一种简单的方法可以在 Cookie 中转换字符串吗?感谢您的帮助
  • 为会话数据创建一个单例类,将来自String cookie = conn.getHeaderField("Set-Cookie"); POST req 的cookie 保存在其中。或者只是use SharedPreferences,保存一个布尔值sessionValid 和一个字符串sessionCookie,在与服务器的所有交互中使用它。 conn.setRequestProperty("Cookie", sessionCookie);
  • 所以我通过 POST 更改了我的 GET 请求以进行测试,因为 POST 请求可以接受字符串中的 cookie 但不能接受 GET 请求。现在它正在工作。我认为它不起作用,因为 cookie 丢失了。感谢您的帮助。
猜你喜欢
  • 2021-12-27
  • 2020-11-13
  • 2019-10-07
  • 2015-01-08
  • 2019-05-13
  • 2019-05-11
  • 2018-10-15
  • 2019-03-27
  • 1970-01-01
相关资源
最近更新 更多