OAuth Error using Aqueduct, mismatched ManagedProp

2019-08-28 22:36发布

问题:

I am using the OAuth hooks provided with a fresh creation of an Aqueduct project. My data is URI encoded in the following way:

var form = body.keys
    .map((key) => "$key=${Uri.encodeQueryComponent(body[key])}")
    .join("&");

I received the following error when attempting to register a User:

DataModelException: Type mismatch for property username on _User, expected assignable type matching ManagedPropertyType.string but got _ImmutableList. #0 ManagedValueBacking.setValueForProperty

The request looks like this:

HttpRequest.request('/register', method: 'POST',
    sendData: form,
    requestHeaders: {
        "Content-Type": "application/x-www-form-urlencoded",
        "Authorization": "Basic $clientCredentials"
}).then((HttpRequest req) {
    ...
}).catchError((e) => _handleError(...));

I am just not too sure why the body is being interpreted as an ImmutableList.

I must be missing something!

回答1:

The /register endpoint expects JSON data.

HttpRequest.request('/register', method: 'POST',
    sendData: JSON.encode(body),
    requestHeaders: {
        "Content-Type": "application/json; charset=utf-8",
        "Authorization": "Basic $clientCredentials"
});

Unfortunately, this isn't quite clear - HTTPController defaults to allowing both JSON and form data and changing it now might break someone's code; the template could do a better job of restricting input to JSON only, though.

This specific reason for this error is that form data and query parameters can have multiple entries for the same key. Aqueduct treats form data and query parameters the same and always parses these types of inputs into lists. Since RegisterController is a QueryController<T>, it is expecting a JSON request body where each value is not a list.

Instead of switching to JSON, you could always modify RegisterController to take only form data:

class RegisterController extends HTTPController {
  RegisterController(this.authServer) {
    acceptedContentTypes = [new ContentType("application", "x-www-form-urlencoded")];
  }
  AuthServer authServer;

  @httpPost
  Future<Response> createUser(
    @HTTPQuery("username") String username,
    @HTTPQuery("password") String password) async {

    var query = new Query<User>()
      ..values.username = username
      ..values.password = password;

    var salt = AuthUtility.generateRandomSalt();
    ...

Note: The endpoints for authorization do expect form data (per the OAuth 2.0 spec), but everything else in a new project expects JSON data.



标签: dart aqueduct