I have a Website written in Spring Boot where you can change your password.
Now I want the user to follow some specific rules ( password length, ... ) for changing his/her password.
My problem is that I get a whole list of users and I cannot use #ValidPassword on this list.
As far as I understand is that you have to use it on fields.
So does my Controller look like:
#PostMapping
public String updateOldPassword(#ModelAttribute
#Valid UserCreationDto userTableSettings,
#RequestParam("radiobutton") String radiobuttonName, BindingResult result, Model model, Errors errors)
This is my UserCreationDto:
public class UserCreationDto {
private List<User> users;
...
And here comes my List where I use the #ValidPassword annotation, however, it is not triggered and I think that I have to move it into my UserCreationDto class but then I cannot use the List<User> anymore.
#Data
public class User {
//#SafeHtml prevents XSS ( Cross-Site Scripting )
#SafeHtml
private String username;
#ValidPassword
private String password;
private String anzeigename;
private String dienstnummer;
private long id;
private Boolean isActive;
}
I hope I described my problem as clearly as possible.
Maybe someone has a good hint for me how to solve this problem.
Thank you very much.
Related
Am working with Spring boot and I am using springdoc-openapi-ui to generate spec files using swagger editor
The issue Is, Am trying to avoid creating model classes just to use them in the request body to show them with swagger UI.
For example :
#RequestMapping(value = "/update/project/{id}", method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> projectUpdate(#RequestBody ObjectNode json, #PathVariable int id)
{ ... }
If I use it like this, the example will be empty on the Swagger UI page.
So as a solution, I have to do it like the following
public class CustomerCreateRequest {
#JsonProperty
private String ProjectId;
#JsonProperty
private String ProjectName;
#JsonProperty
private String ProjectDescription;
#JsonProperty
private String CustomerId;
#JsonProperty
private String CustomerName;
#JsonProperty
private String CustomerDescription;
#JsonProperty
private String BucketId;
#JsonProperty
private String API_KEY;
#JsonProperty
private String Name;
#JsonProperty
private String RedmineId;
And then I can use the model class I just created like the following.
#PostMapping(value = "/createUser")
public ResponseEntity createCustomer(#RequestBody CustomerCreateRequest requestBody)
{ ... }
Question
Is it ok to do a model class just for this purpose?
Is there a way to add an example so the UI team will have an idea of how to use it.
I know that a model class can be helpful in generating a client for UI ( like JSClient ) But is it really necessary? I mean can't we overcome this issue?
Any Answer, Suggestion, Links are appreciated, the swagger docs was not helpful in my case.
my two cents:
Is it ok to do a model class just for this purpose?
Yes, you should use a model class for your #RequestBody becouse every endpoint must have a contract to communicate the payload necessary to be consumed.
It's a good practice add the annotations like
#Parameter(description="Some description", example="{\"foo\":\"bar\"}")
#RequestBody CustomerCreateRequest requestBody
Is there a way to add an example so the UI team will have an idea of how to use it.
No, Swagger will map a POJO class with decorators such as #Schema and others. ObjectNode has not a valid representation for the use case
I know that a model class can be helpful in generating a client for UI ( like JSClient ) But is it really necessary? I mean can't we overcome this issue?
Well, in my experience use tools as Swagger have more benefits than cons. It's necessary take care about the constraints related? I think so
Let me explain a problem. Suppose I have an entity class User:
public class User {
private UUID id;
private String login;
private String password;
private String firstName;
private String lastName;
private String email;
private int age;
// ... more fields and default getters and setters
}
In addition, I have two DTO classes:
public class UserLogin {
private UUID id;
private String login;
// ... getters and setters
}
public class UserLoginEmail {
private UUID id;
private String login;
private String email;
// ... getters and setters
}
Let's take a look to class UserController that has UserLoginEmail as request body and UserLogin as response body:
#RestController("/users")
public class UserController {
#PutMapping
public UserLogin someRequest(UserLoginEmail user) {
// ...
}
}
What is the best way to create some kind of projections in Spring Boot? Can I create an interface with required fields and just put them in the Java method as parameters (or some other way)? I want to build DTO classes with the least effort and agile in my code.
You could use JSON Views with Jackson with which you could define different views on a per endpoint basis (check https://www.baeldung.com/jackson-json-view-annotation for more details).
But in your case, I wouldn't do that. One of your DTOs is a request and the other is a response so you shouldn't mix them together in a single DTO. Even more than that, I don't really like JSON Views because they are simply hard to follow and the code becomes harder to read. Abstractions and code reusability are usually good but it makes the code much harder to read and for the case of DTOs I much more prefer to be explicit and have multiple DTOs even that they are similar. With this approach, you will make it possible to easily change one of the DTOs without affecting anything else, which is not the case when you reuse them in any way.
Having said that, keep both DTOs, but I would rename them: UserLoginRequest and UserLoginResponse.
So lets assume I have 2 model classes - User and Presentation, and they look something like this:
#Entity
public class Presentation {
#Id
private Long id;
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
}
#Entity
public class User implements UserDetails {
#Id
private Long id;
private String username;
private String name;
private String surname;
private String password;
#Enumerated(EnumType.STRING)
private Role role;
}
As you can see I have a unidirectional mapping for user in Presentation class. My endpoint looks something like this:
#RestController
public class PresentationController {
#GetMapping("/{presentationId}")
public PresentationDTO getPresentation(#PathVariable Long presentationId) {
return presentationService.getPresentationById(presentationId);
}
#GetMapping
public List<PresentationDTO> getAllPresentations() {
return presentationService.getAllPresentations();
}
}
Now for my question - how do I change getAllPresentations() to return the presentations that the users with role "user" own, and return all presentations for users with role "admin"? I know I can create a separate endpoint with a different mapping (like /admin/presentations) and add #PreAuthorize(hasRole("admin")), but here is the tricky part.
For the getAllPresentations() endpoint which everyone who is authenticated is supposed to fetch his own presentations, how do I know for which user I have to return his presentations? Maybe I can get the username as a parameter but that might be dangerous cause he can submit any username he wants and get the presentations for that user. I don't know too much about Spring Security and I don't even know the right question to ask google to get an answer so I'm stuck...
Any help will be appreciated, thanks!
You don't have to pass username to your controller method. The currently authenticated user is available through a number of different mechanisms in Spring.The simplest way to retrieve the currently authenticated principal is via a static call to the SecurityContextHolder like this :
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String username = authentication.getName();
So you can refactor you method getAllPresentations() in service class to accept username as argument, and then you can load user by passed username and return presentations for that user.
One way to do what you want is to use #PostFilter annotation to filter List<Presentation> that the authenticated user owns or if the authenticated user has a role ADMIN like this:
#GetMapping
#PostFilter("filterObject.user.username == authentication.principal.username or hasRole('ADMIN')")
public List<PresentationDTO> getAllPresentations() {
return presentationService.getAllPresentations();
}
I have following user details model that is used in POST & PUT controllers of /user resource.
public class UserDetails {
#NotBlank
private String username;
#NotBlank
private String password;
#NotBlank
private String firstName;
#NotBlank
private String lastName;
#NotBlank
private String nic;
#NotNull
private Integer roleId;
// constructor & getters setters
}
#PostMapping("/org/employee")
public void createEmployee(#RequestBody EmployeeDetailsModel empDetails) {
employeeService.createUser(empDetails);
}
#PutMapping("/org/employee")
public void updateEmployee(#RequestBody EmployeeDetailsModel empDetails) {
employeeService.updateUser(empDetails);
}
Here, UserDetails has #NotNull & #NotBlank validations. POST would work fine because to create a user, all details are mandatory. But when updating with PUT, I don't need all properties of UserDetails to be filled.
So my questions are,
How this kind of scenarios are handled? Do we usually force clients to send all those details whether they are changed or not?
Is it possible to disable request body validation just for a particular endpoint or do I have to create separate model that looks the same but without validations?
Seeing your post I can infer that you are interested in modifying the resource
Well to do this you should to use PATCH method instead of PUT.
In PUT you need to send the entire data since it is intended for replacing the resource which is not in the case of the PATCH.
Well in case of the PUT or PATCH we need to ensure that we have an existing resource. Hence before saving it is necessary that we get the original resource from the data store. Then we can modify it with the help of the validation rules on the Entity itself.
so your code should be like.
Considering you have a repository class named as
EmployeeRepository
#PutMapping("/org/employee/{id}")
public void updateEmployee(#RequestBody EmployeeDetailsModel empDetails, #PathVariable("id") int id) {
Optional<Employee> emp = employeeRepo.findById(id);
if (emp.isPresent()) {
// update the new values using setters
// Finally update the resource.
employeeService.updateUser(empDetails);
} else {
throw new ResourceNotFoundException("Your custom msg");
}
}
The repository code should be placed inside the service method ie updateUser but I have placed it here just for demonstration.
I'm currently using the spring-security libraries and I asked myself the following question: How should I combine my database model with the spring-security tables?
As you know spring-security needs two tables (users and authorities) to define an authentication manager in the database. From my pov there are now two possibilities where I store my additional user-information (like email, lastname, last-logged-on, ....)
I could have a plain user-table for authentication purposes and another one for the rest (linked by the username)
I extend the user-table of spring-security with my necessary attributes.
What is the best design from your perspective? What are your experiences?
Lomu
I created a POJO User which represents the User entity as conceived by the Spring Security library, and secondly I created a POJO ProfiledUser to represent a specialized type of user of my application. It is called ProfiledUser because I needed a user associated to a profile. Of course, a similar approach can be applyied for every type of user you need to represent. Basically, if you need more than one type of user you can make your classes to extend the User POJO.
In the following you find the class, with the JPA annotations.
#Entity
#Table(name="USERS")
#Inheritance(strategy=InheritanceType.JOINED)
public class User implements UserDetails {
private static final long serialVersionUID = 1L;
private long id;
private String username;
private String password;
private boolean enabled = true;
Set<Authority> authorities = new HashSet<Authority>();
//...getters & setters
}
#Entity
#Table(name="PROFILED_USERS")
public class ProfiledUser extends User{
private static final long serialVersionUID = 1L;
//some custom attributes
private PersonalData personalData;
private ContactData contactData;
private AddressData addressData;
//...getters & setters
}
If you need to represent only one type of user, I think it should work to add attributes to the User class. However, I prefer to separate the abstract concept of user defined by the Spring Security framework from my business logic. So I'd recommend to implement your own SomethingUser and extend the User class.
A person is a person and you should have a class/table representing a person†.
A user is a user, and is different from a person (hence the two different words), and you should have a class/table representing a user.
Can a person exist without a user? Yes
Can a user exist without a person? No, a username belongs to someone.
#Entity
abstract class Party {
#Id
Long id;
String name;
#OneToMany
List<User> usernames = new ArrayList<>();
}
#Entity
class Individual extends Party {
DateTime dateOfBirth;
}
#Entity
class User {
#ManyToOne
Party party;
String username;
String password; //you better use BCrypt/Blowfish hashing!
Boolean enabled = true;
}
You could instead use a #OneToOne relationship if you only want one username per party.
† Actually you should have a more abstract class/table representing a legal party.