Email or username validation - java

I want to check the email from database through controller and check if the email already exists or not!!! (email = column in db), please suggest me some ideas i'm new here
#RequestMapping(value = "/signup", method = RequestMethod.POST)
public String saveUser(#ModelAttribute User user, Model model) {
if (!user.getName().isEmpty() || !user.getEmail().isEmpty() || !user.getPassword().isEmpty()) {
user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
udao.addUser(user);
return "login";
}
else {
model.addAttribute("error", "fill the form completely!!!");
return "signup";
}
}

Assuming you have the udao as your data access, you just need to create a method that gets the user object given an email id like
#Query(value="select * from users where email = :emailId and isactive=1", nativeQuery=true)
User getUserByEmailId(#Param("emailId")String emailId);
OR
#Query(value="select count(*) from users where email = :emailId and isactive=1", nativeQuery=true)
Integer getUserByEmailId(#Param("emailId")String emailId);
In the option2, you just get the count of the users having the email, a value of 0 indicates that the email is Unique and otherwise.
Once this DAO is completed, you can verify by calling this method and if your response is null, it means that there is no user in the db, else user is present, you can show the end user that the user already exists with the provided email id.
Couple of points for improving the code,
Please do not write your DAO accessing logic in the controller, it is best advised to use a service like UserDetailsService so that all the data access and business rules are applied in the service facilitating SOC, UnitTestability and lot more.
Also, consider using a highly secure algorithm for handling passwords like PBKDF2 which is very secure.
HTH

Assuming that you're using Spring Data JPA you can query the DB in order to check if there is an user with that email, by Spring Data JPA Docs (check the Example 60. Query method declaration in UserRepository):
public interface UserRepository extends Repository<User, Long> {
User findByEmail(String emailAddress);
}
So, in your controller you can do something like:
#Autowired
UserRepository userRepository;
#RequestMapping(value = "/signup", method = RequestMethod.POST)
public String saveUser(#ModelAttribute User user, Model model) {
if (!user.getName().isEmpty() || !user.getEmail().isEmpty() || !user.getPassword().isEmpty()) {
User userFromDb = userRepository.findByEmail(user.getEmail());
// Please note that I'm not sure if it will return null or empty User object, you need to check that
if (userFromDb == null) {
// Do the logic if no email exists in the DB
} else {
// Do the logic if an email exists in the DB
}
}
}

Related

Spring Boot GET method with soft delete how to add another exception in service impl

I'm a beginner in Java and spring boot, and I implemented a User class with CRUD features. However now I need to add the feature that if exclusionFlag is True, the user can't be shown or modified, so I need to add the test if the flag is true before these CRUD actions.
The Code in the moment
UserServiceImpl.java
#Override
public UserResponse getAllUsers(int pageNo, int pageSize, String sortBy, String sortDir) {
Sort sort = sortDir.equalsIgnoreCase(Sort.Direction.ASC.name()) ? Sort.by(sortBy).ascending()
: Sort.by(sortBy).descending();
Pageable pageable = PageRequest.of(pageNo, pageSize, sort);
Page<User> users = userRepository.findAll(pageable);
List<User> listOfUsers = users.getContent();
List<UserDto> content= listOfUsers.stream().map(user -> mapToDTO(user)).collect(Collectors.toList());
UserResponse userResponse = new UserResponse();
userResponse.setContent(content);
userResponse.setPageNo(users.getNumber());
userResponse.setPageSize(users.getSize());
userResponse.setTotalElements(users.getTotalElements());
userResponse.setTotalPages(users.getTotalPages());
userResponse.setLast(users.isLast());
return userResponse;
}
#Override
public UserDto getUserById(long id) {
User user = userRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("User not found"));
//any other addition like:
//User user = userRepository.filterByExclusionFlag(true).orElseThrow(() -> new ResourceNotFoundException("User not found"));
//results in errors like the function can't throw exception and I added the filterByExclusionFlag in UserRepository. Have no idea how to add this feature on UserService
return mapToDTO(user);
}
The best approach is to create a new column in the user's table as exclusion_flag and using constructor DTO projection instead of inbuilt findById with #Query having exlusionFlag as value false.
Save each user with default value for Flag as false. Your sample query will be like this : select needed columns from User where exclusion_flag =false .
And for your modification API (PUT) , ask the client to pass the value fetched from the above (GET) API to pass in the request.The flag passed in the request param helps you to identify if user can be modified or not.

#GetMapping return string info that list is empty

Sometimes there may happen, that in database is nothing, method .findAll() has nothing to show and returns empty body. I know I have return type of this function "List" and I can not directly return string, but how could I send respond body as string or JSON, if list is empty, to let user know? I want to give receiver information that database is empty so it is clear for him.
Class annotations are
#RestController
#RequestMapping(path = "/users")
Code example:
#GetMapping
public Iterable<User> findAll() {
List<User> userList = userRepository.findAll();
if(userList.isEmpty()){
// return "This list is empty :(";
}
return userList;
}
This is more or less something you might do on the front-end. However, what you could return is a POJO that contains the List and a String representing a message about the List, if necessary.
class UserFindAllResponse {
private final List<User> users;
private final String message;
// constructor, getters
}
#GetMapping
public UserFindAllResponse findAll() {
List<User> userList = userRepository.findAll();
return new UserFindAllResponse(userList, userList.isEmpty() ? "There appears to be no users" : "There are x users");
}
In your controller layer, you should return a response mapping with the returned list from the database. Therefore, if it is empty, the value on the front-end will be zero.
So if the length of the userList is empty, we know the DB is empty and you can show a message to the user.
Example front-end Pseudo-code
fetch("${url}/users").then(response => {
if (response.data.length == 0) {
# Show message here, choose whichever way you want
alert("Oh no! Database table was empty")
}
else {
setData(response.data);
}
});
Alternatively, you could choose to throw an error from the back-end and then resolve the error on the front-end and again show a message to the user about the empty DB.
I hope this helps you.

Spring security role-based authorisation best practices

So I basically have a controller method with a PreAuthorize annotation. By default the method will return all projects. The method signature also includes an optional query string (blank query means retrieve all records).
The issue is that if the logged in user is only supposed to view/manage his/her own records, the query string needs to include a filter in it such as "clientId:2".
Now to do that, I was thinking of using the Principal object to retrieve the logged in user and check if he/she is a client as well, then I update the query by adding the required filter to it.
I am just not sure if this is the best approach for this type of issues.
#PreAuthorize("hasAuthority('MANAGE_ALL') OR hasAuthority('VIEW_ALL') OR hasAuthority('MANAGE_OWN')")
#RequestMapping(value = "/projects", method = RequestMethod.GET)
public ResponseEntity<RestResponse> list(Principal principal, #RequestParam(value = "query", required = false, defaultValue = "") String query) {
//If a client is logged in, he/she will have the MANAGE_OWN authority so will need to update the query string to include clientId:<logged-in-client-id>
I would rather move the #PreAuthorize to an application service.
class SomeApplicationService {
UserService userService;
SecurityService securityService;
#PreAuthorize("hasAuthority('MANAGE_ALL') OR hasAuthority('VIEW_ALL') OR hasAuthority('MANAGE_OWN')")
public List<Project> getProjects(String clientId) {
User currentUser = userService.getLoggedInUser();
if(securityService.canManageAllProjects(currentUser))
//get all projects or projects of clientId
else if(securityService.canManageOwnProjects(currentUser))
//get own projects, ignore clientId
}
}

Spring security - Limiting access to my update profile page

I am using spring security in my application and ran into a problem. My application has an Update Profile page. I have added preAuthorized() with request mapping as
#PreAuthorize("isAuthenticated()")
#RequestMapping (value="/user/{uid}/profile/update", method = GET)
public String updateProfileView(#ModelAttribute("form") UserProfileForm form, #PathVariable ("uid") Integer userId, Model model){
It works fine, and unauthenticated user can not access this page.
But the issue is that every Authenticated User can access this page.
For example : User A logged in into application, he/she will be able to update every one's profile.
My CustomUserDetailService class is
#Service
#Transactional
public class CustomUserDetailsService implements UserDetailsService {
#Resource
UserService userService;
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
com.analyst.future.domain.User user = userService.getUser(email);
SimpleGrantedAuthority auth = new SimpleGrantedAuthority("ROLE_USER");
Collection<SimpleGrantedAuthority> authorities = new HashSet<SimpleGrantedAuthority>();
authorities.add(auth);
User userDeatails = new User(user.getEmail(), user.getPassword(), authorities);
return userDeatails;
}
}
I don't think i can restrict it with roles as every authenticated user will have same roles.
Is there any way i can restrict Authenticated user to access only self update profile page.
I am no Spring Security expert, but try reading up on using Expression-Based Access - Link here
There is one tiny little line that matches what you want -
For example, if you wanted a particular method to only allow access to a user whose username matched that of the contact, you could write
#PreAuthorize("#contact.name == authentication.name")
public void doSomething(Contact contact);
I think in your case it would be something like
#PreAuthorize("email == authentication.email")
This is method level though, so maybe not what you are looking for? Good news is that there is a way to use the logged in user and match it against the request user. :)
Since all previous answers talk about matching username (which is included in the principal object) but you need to match the userID, this needs a little more work. We first need to return a custom User object that extends UserDetails. Here is how you can do that:
Step 1: Make your 'User' model implement UserDetails
#Entity
public class UserAccount implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonProperty("id")
private int userId;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
private String email;
private String password;
// other fields and methods
}
You will also have to override some methods from UserDetails, which is easy to figure out.
Step 2: Make you User Service implement UserDetailsService
#Component
public class UserAccountService implements UserDetailsService {
#Override
public UserDetails loadUserByUsername(String username) {
// todo
}
}
Step 3: Return YOUR user model from the loadUserByUsername method
#Override
public UserDetails loadUserByUsername(String username) {
Optional<UserAccount> userAccount = userAccountDao.findByEmail(username);
if (!userAccount.isPresent()) {
throw new MyException("User account not found for the given Username.", HttpStatus.NOT_FOUND);
}
return userAccount.get();
}
Step 4: Add the #PreAuthorize expression to your resource
#PutMapping(value = "/{userId}")
#PreAuthorize("#userId == authentication.principal.userId or hasAuthority('ADMIN')")
public UserAccount updateUserAccount(#PathVariable("userId") int userId,
#RequestBody UserAccount userAccount) {
return userAccountService.updateUserAccount(userId, userAccount);
}
Important things to notice above are:
We can check if the userId is equal above, only because our custom UserAccount model has a userId. If we had returned a raw UserDetail (like org.springframework.security.core.userdetails.User) object instead, it will not have any 'id' property to match with, so above will fail.
Above #PreAuthorize annotation checks for 2 conditions. It allows the request if the user is the owner of the Account or if the user has ADMIN authority.

Access User Data in Spring, Hibernate

I did this tutorial: http://www.mkyong.com/spring-security/spring-security-hibernate-annotation-example/
And it works perfectly. But I don't understand something. I add a new column to my database. It is named FullName. I completed the User class with the setter and getter method. But for example, how can I access this data in the admin page? How can I print out the actual session user's name. Like: Hi , your full name is .
Edit: So how can I acces the logged user's other details, like fullname, address, sex and other stuff like that, not just the username and password?
Edit2: Thanks, it is more clear now. My only question. He converts his own User class to the org.springframework.security.core.userdetails.User. And this class hasn't got a contructor with fullname. So Do I need to create an own UserDetails class override the orginial. Or what have I need to do?
Edit3: Sorry, but i don't understand this. Which service method? Can you show this for me with this example. Thank you very much.
You have add the code in the controller class MainController which is given in the example mentioned in the mkyong site.
#RequestMapping(value = "/admin**", method = RequestMethod.GET)
public ModelAndView adminPage() {
ModelAndView model = new ModelAndView();
model.addObject("title", "Spring Security + Hibernate Example");
model.addObject("message", "This page is for ROLE_ADMIN only!");
model.setViewName("admin");
String fullName = ...; // Add the required logic to get the full name.
model.addObject("FullName", fullName); // Then add the fullName to your model object
return model;
}
Then finally edit the admin.jsp file to display the Full Name.
Update:
The required code is also available in mkyong link. Here is the snippet taken from the same page:
UserDaoImpl.java class has all the code that is needed for your functionality.
List<User> users = new ArrayList<User>();
users = sessionFactory.getCurrentSession()
.createQuery("from User where username=?")
.setParameter(0, username)
.list();
if (users.size() > 0) {
return users.get(0);
} else {
return null;
}
When you get the User object from hibernate it loads all the properties of user, as you have added new field - FullName then this field gets loaded in User object by hibernate if you have proper mapping in hbm files.
This logic is called from the service class MyUserDetailsService using method loadUserByUsername. So take help of this method from service class to get the User details by providing the username input parameter.
Code from service class:
#Transactional(readOnly=true)
#Override
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
com.mkyong.users.model.User user = userDao.findByUserName(username);
List<GrantedAuthority> authorities = buildUserAuthority(user.getUserRole());
return buildUserForAuthentication(user, authorities);
}
// Converts com.mkyong.users.model.User user to
// org.springframework.security.core.userdetails.User
private User buildUserForAuthentication(com.mkyong.users.model.User user, List<GrantedAuthority> authorities) {
return new User(user.getUsername(), user.getPassword(), user.isEnabled(), true, true, true, authorities);
}
As you can see here from above code, a new User object is created at line:
new User(user.getUsername(), user.getPassword(), user.isEnabled(), true, true, true, authorities);
jut update this line to include the Full name and also add the required constructor in User class.

Categories

Resources