Proper place for setting form fields in ResourceSu

2019-08-30 18:36发布

问题:

I have a model for logging in user in my REST API, corresponds to User table (email and password as table columns)

@Entity
public class User {

@Id
@GeneratedValues
private Long id;

private String email;
private String password;

+GET , +SET

}

Then there is @Controller which is making call to above User Entity using JPAService

    @Controller
    @RequestMapping("/rest/auths")
    public class AuthController {

        @Autowired    
        private UserService authService;

        @RequestMapping(value = "/login", method = RequestMethod.POST)
            public @ResponseBody ResponseEntity<AuthLoginFormResource> login(@RequestBody AuthLoginFormResource sentAuth) {

            User user = authService.login(sentAuth.toUser());
            AuthLoginFormResource res = new AuthLoginFormResourceAsm().toResource(user); 

            HttpHeaders headers = new HttpHeaders();
                headers.setLocation(URI.create(res.getLink("self").getHref()));

                return new ResponseEntity<AuthLoginFormResource>(res, HttpStatus.OK);
            }
       }

AuthLoginFormResource : -

        public class AuthLoginFormResource extends ResourceSupport {

            private String email;
            private String password;
            private boolean success;

        public User toUser() { 

            User user = new User(); 
            user.setEmail(email);
            user.setPassword(password);
            //user.setSuccess(false);
            return user;

        }
        +GET, +SET
    }

AuthLoginFormResourceAsm : -

    public class AuthLoginFormResourceAsm extends ResourceAssemblerSupport<User, AuthLoginFormResource> {

        public AuthLoginFormResourceAsm() {
            super(User.class, AuthLoginFormResource.class);
        }

        @Override
        public AuthLoginFormResource toResource(User user) {

            AuthLoginFormResource res = new AuthLoginFormResource();
            res.setEmail(user.getEmail());
            res.setPassword(user.getPassword());
            //res.setSuccess(user.isSuccess()); // Success is not existing in USER

            res.add(linkTo(AuthController.class).withSelfRel());

            return res;
        }

    }

There are 2 issues -

  • I need to send a success flag as boolean in response for which i have added a boolean success to AuthLoginFormResource. But, AuthLoginFormResource gets set only from AuthLoginFormResourceAsm.toResource method , which in turn does it from entity User. As User entity models database where there is no success column, I am not able to set success at this place.

    So, should I add dummy success field to User Entity and set that from service method , though there is no such field in database or create a new Entity representing Login Form here and return that ?

  • Same problem with another field that is a token for authentication which does not exist in database but is part of response.

What is correct place for setting such fields in ResourceSupport object - inside database Entity and return from Service / creating another Form Model entity on top of Domain Model and return from service.

This is basic question I am facing in many places where data model and forms don't match one to one.

回答1:

I strongly recommend the following;

  1. Modify UserService.login method to return true or false based on successfull authentication instead of retrieved user object from database.
  2. Return only true or false with status OK and FAIL, as part of the response not the entire AuthLoginFormResource. This is a bad practice because you are sending out the username and password as part of the request and response, back and forth in a roundtrip. If someone is evesdropping they can easily figure out what username passwords work and what don't.

Or

Consider using Basic Authorization, Digest Authorization or OAuth if you fancy than this custom Authentication Implementation. Using Spring Security you can achieve any of the aforementioned really easily.