I have a class (Account) that represents the user's system. Account contains a field role. It is the enum that contains three cases.
Account class
public class Account extends Model {
#Id
#Email
public String email;
#Required
#NotNull
public String password;
#Required
#NotNull
public String firstName;
#Required
#NotNull
public String lastName;
#Required
public String phone;
public MyRole role;
MyRole
public enum MyRole {
ADMIN,
TEACHER,
USER
}
How can I implement an authorization?
I think you could use Deadbolt-2 library, listed in the Play Framework plugins.
In the same idea of not reinvent the wheel, did you take a look at the Play-Authenticate plugin ? An another advantage of this last one is that it is compatible with Deadbolt-2.
Deadbolt-2 library is a solution. However, if you want to build your very own one, firstly, you need to read https://www.playframework.com/documentation/2.4.x/ScalaActionsComposition.
Actually, it is not that difficult and you can implement almost unlimited, very flexiable solution.
The basic idea is to define a UserAuthAction, like:
#Singleton
class UserAuthAction #Inject() (principalService: PrincipalService) extends ActionBuilder[Request] with ActionFilter[Request] {
override protected def filter[A](request: Request[A]) = Future.successful {
request.session.get(principalService.accessTokenCacheKey).map { accessToken =>
if (principalService.authenticate(accessToken))
None
else
Some(Results.Redirect(routes.PrincipalController.login()))
} getOrElse {
Some(Results.Redirect(routes.PrincipalController.login()))
}
}
}
And then compose it with the actions the do the actually job. For example:
#Singleton
class Application #Inject() (userAuthAction: UserAuthAction) extends Controller {
def index = (userAuthAction andThen anyAction) { request =>
Ok(views.html.index())
}
}
Along the way, if you are using ActionRefiner, you can even extract additional user information and provide it to the latter actions, such as anyAction above.
Related
Consider the following pojo for reference:
public class User{
private String username;
private String firstName;
private String middleName;
private String lastName;
private String phone;
//getters and setters
}
My application is a basically spring-boot based REST API which exposes two endpoints, one to create the user and the other to retrieve a user.
The "users" fall into certain categories, group-a, group-b etc. which I get from the headers of the post request.
I need to validated the user data in runtime and the validations may differ based on the group of a user.
for example, the users that fall into group-a may have phone numbers as an optional field whereas it might be a mandatory field for some other group.
The regex may also vary based on their groups.
I need to be able to configure spring, to somehow dynamically validate my pojo as soon as they are created and their respective set of validations get triggered based on their groups.
Maybe I can create a yml/xml configuration which would allow me to enable this?
I would prefer to not annotate my private String phone with #NotNull and #Pattern.
My configuration is as follows:
public class NotNullValidator implements Validator {
private String group;
private Object target;
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
#Override
public void validate(Object o) {
if (Objects.nonNull(o)) {
throw new RuntimeException("Target is null");
}
}
}
public interface Validator {
void validate(Object o);
}
#ConfigurationProperties(prefix = "not-null")
#Component
public class NotNullValidators {
List<NotNullValidator> validators;
public List<NotNullValidator> getValidators() {
return validators;
}
public void setValidators(List<NotNullValidator> validators) {
this.validators = validators;
}
}
application.yml
not-null:
validators:
-
group: group-a
target: user.username
-
group: group-b
target: user.phone
I want to configure my application to somehow allow the validators to pick their targets (the actual objects, not the strings mentioned in the yml), and invoke their respective public void validate(Object o) on their targets.
P.S.
Please feel free to edit the question to make it better.
I am using jackson for serializing and deserializing JSON.
The easiest solution to your problem, as i see it, is not with Spring or the POJOs themselves but with a design pattern.
The problem you're describing is easily solved by a strategy pattern solution.
You match the strategy to use by the header you're expecting in the request, that describes the type of user, and then you perform said validations inside the strategy itself.
This will allow you to use the same POJO for the whole approach, and deal with the specifics of handling/parsing and validating data according to the each type of user's strategy.
Here's a link from wiki books with a detailed explanation of the pattern
Strategy Pattern
Suppose you have a basic interface for your strategies:
interface Strategy {
boolean validate(User user);
}
And you have 2 different implementations for the 2 different types of user:
public class StrategyA implements Strategy {
public boolean validate(User user){
return user.getUsername().isEmpty();
}
}
public class StrategyB implements Strategy {
public boolean validate(User user){
return user.getPhone().isEmpty();
}
}
You add a Strategy attribute to your User POJO and assign the right implementation of the Strategy to that attribute when you receive the post request.
Everytime you need to validate data for that user you just have to invoke the validate method of the assigned strategy.
If each User can fit multiple strategies, you can add a List<Strategy> as an attribute instead of a single one.
If you don't want to change the POJO you have to check which is the correct strategy every time you receive a post request.
Besides the validate method you can add methods to handle data, specific to each strategy.
Hope this helps.
You can use validation groups to control which type of user which field gets validated for. For example:
#NotBlank(groups = {GroupB.class})
private String phone;
#NotBlank(groups = {GroupA.class, GroupB.class})
private String username;
Then you use the headers from the request that you mentioned to decide which group to validate against.
See http://blog.codeleak.pl/2014/08/validation-groups-in-spring-mvc.html?m=1 for a complete example.
Updated to include a more comprehensive example:
public class Val {
private Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
public boolean isValid(User user, String userType) {
usergroups userGroup = usergroups.valueOf(userType);
Set<ConstraintViolation<User>> constraintViolations = validator.validate(user, userGroup.getValidationClass());
return constraintViolations.isEmpty();
}
public interface GroupA {}
public interface GroupB {}
public enum usergroups {
a(GroupA.class),
b(GroupB.class);
private final Class clazz;
usergroups(Class clazz) {
this.clazz = clazz;
}
public Class getValidationClass() {
return clazz;
}
}
}
This doesn't use application.yaml, instead the mapping of which fields are validated for each group is set in annotations, similar results using Spring's built in validation support.
I was able to solve my problem with the use of Jayway JsonPath.
My solution goes as follows:
Add a filter to your API which has the capability to cache the InputStream of the ServletRequest since it can be read only once. To achieve this, follow this link.
Create a bunch of validators and configure them in your application.yml file with the help of #ConfigurationProperties. To achieve this, follow this link
Create a wrapper which would contain all your validators as a list and initialize it with #ConfigurationProperties and the following configuration:
validators:
regexValidators:
-
target: $.userProfile.lastName
pattern: '[A-Za-z]{0,12}'
group: group-b
minMaxValidators:
-
target: $.userProfile.age
min: 18
max: 50
group: group-b
Call the validate method in this wrapper with the group which comes in the header, and then call the validate of the individual validators. To achieve this, I wrote the following piece of code in my wrapper:
public void validate(String input, String group) {
regexValidators.stream()
.filter(validator -> group.equals(validator.getGroup()))
.forEach(validator -> validator.validate(input));
minMaxValidators.stream()
.filter(validator -> group.equals(validator.getGroup()))
.forEach(validator -> validator.validate(input));
}
and the following method in my validator:
public void validate(String input) {
String data = JsonPath.parse(input).read(target);
if (data == null) {
throw new ValidationException("Target: " + target + " is NULL");
}
Matcher matcher = rule.matcher(data);
if (!matcher.matches()) {
throw new ValidationException("Target: " + target + " does not match the pattern: " + pattern);
}
}
I have created a functioning project to demonstrate the validations and it can be found here.
I understand that the answer alone might not be very clear, please follow the above mentioned url for the complete source code.
I have a scenario where a property has a different validation applied depending on end-point. This is done via "groups" (code example below & reference to dropwizard doc: http://www.dropwizard.io/0.9.3/docs/manual/validation.html#validated).
I implemented the DropWizard validations but the Swagger does not recognizing the "groups" and therefore doesn't provided correct model description. In addition Swagger doesn't seem to have any annotations that would accomplish the scenario.
Can you please help?
Thank you.
public interface Version1FirstName { }
public interface Version2FirstName { }
class Person {
#NotEmpty(groups = Version1FirstName .class)
#Length(max = 5, groups = Version2FirstName .class)
private firstName;
private lastName;
}
#POST
#Path("/v1")
public void addName(#Validated(Version1FirstName.class) Person person) {}
#POST
#Path("/v2")
public void retriveName(#Validated({Version2FirstName.class,
Version1FirstName.class}) Person person) {}
I am considering moving from Hibernate to jOOQ but I can't find e.g.
how to have Pattern-Constraints on a String like this in Hibernate:
#NotEmpty(message = "Firstname cannot be empty")
#Pattern(regexp = "^[a-zA-Z0-9_]*$", message = "First Name can only contain characters.")
private String firstname;
How would I do that in jOOQ?
The "jOOQ way"
The "jOOQ way" to do such validation would be to create either:
A CHECK constraint in the database.
A trigger in the database.
A domain in the database.
After all, if you want to ensure data integrity, the database is where such constraints and integrity checks belong (possibly in addition to functionally equivalent client-side validation). Imagine a batch job, a Perl script, or even a JDBC statement that bypasses JSR-303 validation. You'll find yourself with corrupt data in no time.
If you do want to implement client-side validation, you can still use JSR-303 on your DTOs, which interact with your UI, for instance. But you will have to perform validation before passing the data to jOOQ for storage (as artbristol explained).
Using a Converter
You could, however, use your own custom type by declaring a Converter on individual columns and by registering such Converter with the source code generator.
Essentially, a Converter is:
public interface Converter<T, U> extends Serializable {
U from(T databaseObject);
T to(U userObject);
Class<T> fromType();
Class<U> toType();
}
In your case, you could implement your annotations as such:
public class NotEmptyAlphaNumericValidator implements Converter<String, String> {
// Validation
public String to(String userObject) {
assertNotEmpty(userObject);
assertMatches(userObject, "^[a-zA-Z0-9_]*$");
return userObject;
}
// Boilerplate
public String from(String databaseObject) { return databaseObject; }
public Class<String> fromType() { return String.class; }
public Class<String> toType() { return String.class; }
}
Note that this is more of a workaround, as Converter hasn't been designed for this use-case, even if it can perfectly implement it.
Using formal client-side validation
There's also a pending feature request #4543 to add more support for client-side validation. As of jOOQ 3.7, this is not yet implemented.
I recommend you don't try to use jOOQ in a 'hibernate/JPA' way. Leave the jOOQ generated classes as they are and map to your own domain classes manually, which you are free to annotate however you like. You can then call a JSR validator before you attempt to persist them.
For example, jOOQ might generate the following class
public class BookRecord extends UpdatableRecordImpl<BookRecord> {
private String firstname;
public void setId(Integer value) { /* ... */ }
public Integer getId() { /* ... */ }
}
You can create your own domain object
public class Book {
#NotEmpty(message = "Firstname cannot be empty")
#Pattern(regexp = "^[a-zA-Z0-9_]*$", message = "First Name can only contain characters.")
private String firstname;
public void setId(Integer value) { /* ... */ }
public Integer getId() { /* ... */ }
}
and map by hand once you've retrieved a BookRecord, in your DAO layer
Book book = new Book();
book.setId(bookRecord.getId());
book.setFirstname(bookRecord.getFirstname());
This seems quite tedious (and ORM tries to spare you this tedium) but actually it scales quite well to complicated domain objects, in my opinion, and it's always easy to figure out the flow of data in your application.
Is there a way to set resource relations through annotations? I made a similar question a some time ago but i've not been clear enough. I want to have something like this:
public class UserResource {
private String username;
#Relation(value = "{servicebaseUrl}/classes/${value}", rel = "class")
private String classId;
// Getters and setters
}
And then add a message converter which would add links only if client sends Accept = application/hal+json, avoiding the fact of doing two different controller endpoints for application/hal+json and application/json. Does Spring offers something like that? I found that it actually offers this #Relation annotation(or similar one) but it seems that it is not for the same purposes.
No this is not possible - you would have to implement a ResourceAssembler to add links to your resources.
Usually your resources extend ResourceSupport.
class PersonResource extends ResourceSupport {
String firstname;
String lastname;
}
Then your create ResourceAssembler to control the creation of that resource:
class PersonResourceAssembler extends ResourceAssemblerSupport<Person, PersonResource> {
public PersonResourceAssembler() {
super(PersonController.class, PersonResource.class);
}
#Override
public PersonResource toResource(Person person) {
PersonResource resource = createResource(person);
// … do further mapping and add links
resource.add(new Link("http://myhost/people"));
return resource;
}
}
See the spring hateoas documentation for details
There are a lot of articles here and all over the web, but these all target different Objectify versions and seem not to work for one or the other reason.
I have an entity, which references another entity (e.g. an Account entity references a User entity):
#Cache
#Entity
public final class Account {
#Id Long id;
#Index private Ref<User> user;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public User getUser() {
return user.get();
}
public void setUser(User user) {
this.user = Ref.create(user);
}
}
I am trying to do this:
From the client, GET the account entity over REST/Google Cloud Endpoints.
Modify the resource.
UPDATE it on the server.
As discussed here Objectify loads object behind Ref<?> even when #Load is not specified above code always returns the referenced user as well, whích I don't want.
One option would be, as #svpino suggested, "Make your #ApiMethod return a different Account object without the user property (thus avoiding fetching the user if you don't need it)." This works as long as I don't want to UPDATE the resource. If I need to UPDATE, the Key/Ref needs to be preserved (even though I don't need it on the client).
One possible approach that I can see would be using Key instead of Ref and rendering a web-safe string, then recreating the user during UPDATE.
private Key<User> user;
public String getUser() {
return user.toString();
}
public void setUser(String user) {
this.user = Key.create(user);
}
The string looks like "Key(User(5723348596162560))", but it seems not to be reconstituted (at least I get an exception here, haven't tracked it down yet).
Another approach would be writing an #ApiTransformer, which did not solve the problem either.
Jeff #StickFigure posted several times during the last years and the issue still seems not to be solved.
What's the current state with Objectify 5.0.2 and what's the recommendation for preserving the key between roundtrips, when the key is not needed on the client?
You need to annotate the property that you want to omit with #ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
Google documentation says the following about the #ApiResourceProperty:
#ApiResourceProperty provides provides more control over how resource
properties are exposed in the API. You can use it on a property getter
or setter to omit the property from an API resource. You can also use
it on the field itself, if the field is private, to expose it in the
API. You can also use this annotation to change the name of a property
in an API resource.
I encourage you to read more by visiting this link
https://developers.google.com/appengine/docs/java/endpoints/annotations#apiresourceproperty
So in your case your class should look like this after the modification.
#Cache
#Entity
public final class Account
{
#Id Long id;
#Index private Ref<User> user;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
public User getUser() {
return user.get();
}
#ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
public void setUser(User user) {
this.user = Ref.create(user);
}
}
The following code serializes an entity object to a web-safe string so it can be transferred over REST. When the entity is sent back to the server, the Ref<> is reconstituted. This way a server-side reference is not lost while the object does a round-trip to the client. This way referenced objects are not transferred to the client and back, but can be "worked" as Ref<> on the client.
#Index private Ref<User> user;
// for serialization
public String getUser() {
return user.getKey().getString(); // .toWebSafeString() will be added in future version of objectify and .toWebSafeString() will do the same as .getString()
}
public void setUser(String webSafeString) {
Key<User> key = Key.create(webSafeString);
this.user = Ref.create(key);
}
Two separate functions (not named well, I admit) are there for loading the actual object on the server and for creating the reference in the first place:
// for load and create reference
public User loadUser() {
return user.get();
}
public void referenceUser(User user) {
this.user = Ref.create(user);
}
I hope this solves the problem for everybody. This did not yet go through thorough testing, so comments are still welcome.
I have run a test to compare between using a Key<> and a Ref<> and to me it looks like even with Ref<> the entity is only reconstituted when loadEntity()/.get() is called. So Ref<> if probably better as #Load annotations will work. Maybe the objectify guys can confirm this.
You can create a class that extends Ref<User> and use an #ApiTransformer to transfer that class between backend and client
#ApiTransformer(UserRefTransformer.class)
public class UserRef extends LiveRef<User>
{
}
public class UserRefTransformer implements Transformer<UserRef, User>
{
// Your transformation code goes here
}