1

我正在 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();
                }

             }
        }

      }
}

并尝试使用浏览器:user1/password1

http://example.com:4040/login

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

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

谢谢你的帮助。

4

1 回答 1

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;

URLConnection默认情况下, Android会自动遵循重定向,并正在获取您返回的数据/loginSuccess

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

所以解决方案是

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

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

    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")"

于 2014-10-09T00:14:04.000 回答