I want to create a login method for my spring application. But when I try to call the
getUserByAuthentication
method, I get a null pointer exception. Here is my code:
Function calling the error:
#PostMapping(path = "/online")
public ResponseEntity<?> onlineRequest(#RequestBody OnlineRequest onlineRequest) {
User user = null;
UserManager userManager = new UserManager();
user = userManager.getUserByAuthentication(onlineRequest.getUsername(), onlineRequest.getPassword());
if (user!=null){
user.setLatestTimeStamp(System.currentTimeMillis());
return new ResponseEntity<>("You are now online, Enjoy!", HttpStatus.OK);
} else {
return new ResponseEntity<>("Invalid login", HttpStatus.valueOf(403));
}
}
Get User by Authentication class:
public class UserManager {
#Autowired
private UserRepository userRepository;
public User getUserByID(int id){
return userRepository.findById(id).get();
}
public User getUserByAuthentication(String name, String password){
Iterable<User> userList = userRepository.findAll();
ArrayList<User> users = new ArrayList<>();
userList.forEach(users::add);
User user = null;
for (User u : users){
if (u.getUsername().equals(name) && u.getPassword().equals(password)){
user = u;
}
}
return user;
}
}
Repository:
#Repository
public interface UserRepository extends CrudRepository<User, Integer> {
}
User class:
#Entity
#Table
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
//Initialize
private String username;
private String password;
private boolean hasAccess;
ArrayList<Integer> inChannels;
long latestTimeStamp;
public long getLatestTimeStamp() {
return latestTimeStamp;
}
public void setLatestTimeStamp(long latestTimeStamp) {
this.latestTimeStamp = latestTimeStamp;
}
public ArrayList<Integer> getInChannels() {
return inChannels;
}
public void setInChannels(ArrayList<Integer> inChannels) {
this.inChannels = inChannels;
}
public Long getId() {
return id;
}
public User() {
}
public boolean hasAccess() {
return hasAccess;
}
public void setAccess(boolean hasAccess) {
this.hasAccess = hasAccess;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
You can't use #Autowired without one of the annotation that define a component in spring, so in your case, you can use #Service on UserManager like this:
#Service
public class UserManager {
and also don't use static on your method, you have to inject the UserManager component in the controller, as you do with your repository:
#Autowired
private UserManager userManager;
Then you can use:
user = userManager.getUserByAuthentication(onlineRequest.getUsername(), onlineRequest.getPassword());
^^^^^^^^^^^
I fixed it by adding the find function into the repository interface.
Related
I have already done connect MongoDB using application.properties. But I want to connect MongoDB through mongoose.
This is my current configuration
This is DB Connection url setting in application.properties;
spring.data.mongodb.uri =mongodb+srv://hans123:Hans123#cluster0.avxi858.mongodb.net/?retryWrites=true&w=majority
spring.data.mongodb.database=test
spring.data.mongodb.port=27017
spring.data.mongodb.host=localhost
Model Class
#Document
#AllArgsConstructor
#NoArgsConstructor
#Data
public class User {
#Id
#Indexed
private String id;
#Indexed
private String address;
#Indexed
private String name;
#Indexed
private String email;
#Indexed
private String password;
#Indexed
private String role;
}
Repository Class
public interface userReporsitory extends MongoRepository<User,String> {
Optional<User> findByEmail(String email);
List<User> findAllByRole(String role);
}
Service Class
#AllArgsConstructor
#Service
public class userService {
private userReporsitory userReporsitory;
public User saveUser(User user){
return userReporsitory.save(user);
}
public User login(User user){
User response = userReporsitory.findByEmail(user.getEmail()).orElseThrow(()->new RuntimeException("User Not Found"));
if(!response.getPassword().equals(user.getPassword())){
throw new RuntimeException("Bad Credincials");
}
return response;
}
public List<User> findAllUsers(){
return userReporsitory.findAllByRole("user");
}
}
Controller Class
#CrossOrigin
#RestController
#AllArgsConstructor
#RequestMapping("api/v1/user")
public class userController {
private userService userService;
#PostMapping("/create")
public ResponseEntity<User> save(#RequestBody User user){
HttpStatus status = HttpStatus.EXPECTATION_FAILED;
User response = userService.saveUser(user);
if(response != null){
status = HttpStatus.CREATED;
}
return new ResponseEntity<>(response, status);
}
#PostMapping("/login")
public ResponseEntity<User> login(#RequestBody User user){
return new ResponseEntity<>(userService.login(user),HttpStatus.ACCEPTED);
}
#GetMapping("/userList")
public ResponseEntity<List<User>> userList(){
return new ResponseEntity<>(userService.findAllUsers(),HttpStatus.ACCEPTED);
}
}
In above answer you can encrypt the password as well (Additional Thing)
AuthRequest Class:
#Data
#AllArgsConstructor
public class AuthRequestDto {
private String userName;
private String password;
}
RegisterRequest Class:
#Data
#AllArgsConstructor
public class RegisterRequestDto {
private String userName;
private String password;
private String firstName;
private String email;
private String phone;
private String address;
}
UserService Class:
#AllArgsConstructor
#Service
public class UserService implements UserDetailsService {
private final UserRepository userRepository;
private final JWTUtility jwtUtility;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserEntity userEntity = userRepository.findByUsername(username).orElseThrow(()-> new UsernameNotFoundException("user name not found"));
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(userEntity.getRole());
return new User(userEntity.getUsername() , userEntity.getPassword() , new ArrayList<>(Arrays.asList(authority)));
}
public UserEntity registerUser(RegisterRequestDto request){
//check user is already in
if(userRepository.existsByUsernameIgnoreCase(request.getUserName())){
throw new FieldValidationFaild("user name already exist in the system");
}
if(userRepository.existsByEmailIgnoreCase(request.getEmail())){
throw new FieldValidationFaild("email already exist in the system");
}
UserEntity saveToBe = UserEntity.builder()
.username(request.getUserName())
.password(new BCryptPasswordEncoder().encode(request.getPassword()))
.firstName(request.getFirstName())
.email(request.getEmail())
.phone((request.getPhone()))
.address(request.getAddress())
.role(Role.BUYER)
.build();
return userRepository.save(saveToBe);
}
public AuthRespondDto loginUser(AuthRequestDto authRequestDto){
final UserDetails userDetails = loadUserByUsername(authRequestDto.getUserName());
final String token = jwtUtility.generateToken(userDetails);
return new AuthRespondDto(token , authRequestDto.getUserName() , userDetails.getAuthorities().stream().findFirst().get().getAuthority());
}
public long getAuthUserId(String username){
UserEntity userEntity = userRepository.findByUsername(username).get();
return userEntity.getId();
}
public String getUserAddressByName(String username){
UserEntity userEntity = userRepository.findByUsername(username).get();
return userEntity.getAddress();
}
public String getUserPhoneByName(String username){
UserEntity userEntity = userRepository.findByUsername(username).get();
return userEntity.getPhone();
}
public String getUserEmailByName(String username){
UserEntity userEntity = userRepository.findByUsername(username).get();
return userEntity.getEmail();
}
public UserEntity getUserById(long id){
return userRepository.findById(id).orElseThrow(()-> new NotFoundException("user not found"));
}
}
AuthController Class (Controller Class):
public class AuthController {
private final AuthenticationManager authenticationManager;
private final UserService userService;
#PostMapping("/signin")
public ResponseEntity<AuthRespondDto> login(#RequestBody AuthRequestDto authRequestDto) throws BadCredentialsException {
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
authRequestDto.getUserName(),
authRequestDto.getPassword()
)
);
}catch (BadCredentialsException e){
//TODO add proper exception
throw new BadCredentialsException("INVALID_USERNAME_OR_PASSWORD" , e);
}
return new ResponseEntity<>(userService.loginUser(authRequestDto) , HttpStatus.ACCEPTED);
}
#PostMapping("/signup")
public ResponseEntity<UserEntity> register(#RequestBody RegisterRequestDto request){
// basic controller level validations
if(request.getUserName().isEmpty()){
throw new FieldValidationFaild("user name is required");
}
if(request.getPassword().isEmpty()){
throw new FieldValidationFaild("password is required");
}
if(request.getFirstName().isEmpty()){
throw new FieldValidationFaild("first name is required");
}
if(request.getEmail().isEmpty()){
throw new FieldValidationFaild("email is required");
}
if(request.getPhone().isEmpty()){
throw new FieldValidationFaild("phone is required");
}
if(request.getPhone().length() != 10){
throw new FieldValidationFaild("phone number length must be 10");
}
if(request.getAddress().isEmpty()){
throw new FieldValidationFaild("address is required");
}
return new ResponseEntity<>(userService.registerUser(request) , HttpStatus.CREATED);
}
}
I would like to learn, how can I make a project that has this function. (sign-in and sign-up)
These are the classes that I have so far.
this is the entity i have also the class User
#Entity(name = "Users")
public class UserEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id" ,nullable = false)
private int id;
#Column(name = "first_name" )
private String firstname;
#Column(name = "last_name" )
private String lastname;
#Column(name = "Email" )
private String email;
protected UserEntity() {
}
public UserEntity( String firstname, String lastname, String email) {
this.firstname = firstname;
this.lastname = lastname;
this.email = email;
}
this is the Service class where the methods should be
#Service
public class UserService {
private final UserRepository usersRepository;
public UserService(UserRepository usersRepository) {
this.usersRepository = usersRepository;
}
public List<User> findAll (){
List<UserEntity> users = usersRepository.findAll();
return users.stream().map(this::entityToUser).collect(Collectors.toList());
}
public User findUserbyId(int id){
var userentity = usersRepository.findById(id);
return userentity.map(this::entityToUser).orElse(null);
}
public User update(int id , UserCreateRequest request){
var userEntityOptional = usersRepository.findById(id);
if(userEntityOptional.isEmpty()){
return null;
}
var userEntity = userEntityOptional.get();
userEntity.setFirstname(request.getFirstname());
userEntity.setLastname(request.getLastname());
userEntity.setEmail(request.getEmail());
usersRepository.save(userEntity);
return entityToUser(userEntity);
}
public boolean deleteById(int id){
if (!usersRepository.existsById(id)){
return false;
}
usersRepository.existsById(id);
return true;
}
public User create(UserCreateRequest request){
var userEntity = new UserEntity(request.getFirstname(),request.getLastname(),request.getEmail());
userEntity = usersRepository.save(userEntity);
return entityToUser(userEntity);
}
public User entityToUser(UserEntity userEntity){
return new User (
userEntity.getId(),
userEntity.getFirstname(),
userEntity.getLastname(),
userEntity.getEmail());
}
}
here is the User Controller
#RestController
public class UserRestController {
private final UserService userService;
public UserRestController(UserService userService) {
this.userService = userService;
}
#GetMapping(path = "/api/v1/users")
public ResponseEntity<List<User>> fetchUsers() {
return ResponseEntity.ok(userService.findAll()) ;
}
I would like to know what do I need exactly to get this function right in an optimal way
what are the necessary steps?
#Service
public class UserService {
//make this Autowired
#Autowired
private UserRepository usersRepository;
public List<User> findAll (){
List<UserEntity> users = usersRepository.findAll();
return users.stream().map(this::entityToUser).collect(Collectors.toList());
}
public User findUserbyId(int id){
var userentity = usersRepository.findById(id);
return userentity.map(this::entityToUser).orElse(null);
}
public User update(int id , UserCreateRequest request){
var userEntityOptional = usersRepository.findById(id);
if(userEntityOptional.isEmpty()){
return null;
}
var userEntity = userEntityOptional.get();
userEntity.setFirstname(request.getFirstname());
userEntity.setLastname(request.getLastname());
userEntity.setEmail(request.getEmail());
usersRepository.save(userEntity);
return entityToUser(userEntity);
}
public boolean deleteById(int id){
if (!usersRepository.existsById(id)){
return false;
}
usersRepository.existsById(id);
return true;
}
public User create(UserCreateRequest request){
var userEntity = new UserEntity(request.getFirstname(),request.getLastname(),request.getEmail());
userEntity = usersRepository.save(userEntity);
return entityToUser(userEntity);
}
public User entityToUser(UserEntity userEntity){
return new User (
userEntity.getId(),
userEntity.getFirstname(),
userEntity.getLastname(),
userEntity.getEmail());
}
}
here is the User Controller
#RestController
public class UserRestController {
//make this Autowired
#Autowired
private UserService userService;
#GetMapping(path = "/api/v1/users")
public ResponseEntity<List<User>> fetchUsers() {
return ResponseEntity.ok(userService.findAll()) ;
}
Check this to know more about #Autowired https://www.baeldung.com/spring-autowire
I have been trying to add a create method to my spring boot security app but, when I use post mapping I get that error. Also, my id is auto-incremented in db. I am not sure but maybe the error is because of it. I don't know how to write an auto-incremented value in the request body.
{"timestamp":"2020-08-
23T00:43:31.062+00:00","status":403,"error":"Forbidden","message":"","path":"/createUser"}
The body that i am trying to post:
{
"id": 3,
"userName": "Adminn",
"password": "pss",
"active": true,
"role": "ROLE_ADMIN"
}
Request Body for Post Mapping
[1]: https://i.stack.imgur.com/uqoD0.png
My home resource class
package io.javabrains.springsecurity.jpa;
#RestController
public class HomeResource {
#Autowired
private UserRepository userRepo;
#GetMapping("/")
public String home() {
return ("<h1>Welcome</h1>");
}
#GetMapping("/user")
public String user() {
return ("Welcome User");
}
#GetMapping("/admin")
public String admin() {
return ("<h1>Welcome Admin</h1>");
}
#GetMapping("/users/{id}")
public Optional<User> retriveUser(#PathVariable int id)
{
return userRepo.findById(id);
}
#PostMapping("/createUser")
public void createUser(#RequestBody User myuser) {
User savedUser=userRepo.save(myuser);
}
/*#GetMapping("/createUser") // it is working
public String addUser() {
User newuser= new User();
newuser.setUserName("new");
newuser.setPassword(new BCryptPasswordEncoder().encode("pass"));
newuser.setRole("ROLE_ADMIN");
newuser.setActive(true);
userRepo.save(newuser);
return "user booked";
}*/
}
My Spring App Class
#SpringBootApplication
#EnableJpaRepositories(basePackageClasses = UserRepository.class)
public class SpringsecurityApplication implements CommandLineRunner{
#Autowired
UserRepository userRepository;
public static void main(String[] args) {
SpringApplication.run(SpringsecurityApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
// TODO Auto-generated method stub
System.out.println("Application Running.");
User adminUser= new User();
adminUser.setUserName("Admin");
adminUser.setPassword(new BCryptPasswordEncoder().encode("pass"));
adminUser.setRole("ROLE_ADMIN");
adminUser.setActive(true);
userRepository.save(adminUser);
User newUser= new User();
newUser.setUserName("User");
newUser.setPassword(new BCryptPasswordEncoder().encode("pass"));
newUser.setRole("ROLE_USER");
newUser.setActive(true);
userRepository.save(newUser);
}
}
User Class
package io.javabrains.springsecurity.jpa.models;
#Entity
#Table(name="app_user")
public class User {
#Id
#GeneratedValue(strategy =GenerationType.AUTO)
private int id;
private String userName;
private String password;
private boolean active;
private String role;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
Security Config Class
package io.javabrains.springsecurity.jpa;
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder ()
{
return new BCryptPasswordEncoder();
}
#Autowired
UserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin").hasAnyRole("ADMIN")
.antMatchers("/user").hasAnyRole("ADMIN","USER")
.antMatchers("/","/createUser").permitAll()
.and().formLogin();
}
}
Because CSRF protection for state-changing HTTP verbs, such as POST, is enabled by default. You can either disable it or include CSRF token in your web page, and subsequently in your HTTP request.
What if you modify your code this way:
.antMatchers(HttpMethod.POST, "/createUser").permitAll()
First of all is a bad practice try to map the JSON request to an entity class. First you should use a DTO class.
Do that first and see what happend
I'm trying to add a global form to where a user can post. I get that error for some reason, been working on this for a while, it must be something with my controller but not sure
in home.jsp
<form:form modelAttribute= "tweets">
<form:input path="tweet" />
<input id="user" name="user" type="hidden" value="${user}"/>
<input type="submit" value="send" />
</form:form>
in TweetsController
public class TweetsController {
private TweetsService tweetsService;
#ModelAttribute("tweets")
// name for tweet form in home public Tweets
public Tweets construct() {
return new Tweets();
}
// //----------------------------------------------------------------------
#RequestMapping(value = "/")
public String newTweet(Model model) {
model.addAttribute("tweets", new Tweets());
return "/home";
}
#RequestMapping(method = RequestMethod.GET)
public String tweet(Model model) throws MessagingException {
// key value - attribute and the value of the attribute
// if key isn't passed, it will default to camelCased class name
model.addAttribute("tweets", new CreateTweet());
return "home";
}
#RequestMapping(method = RequestMethod.POST)
public String tweet(#ModelAttribute("tweets") CreateTweet tweet, BindingResult result,
RedirectAttributes redirectAttributes) {
if (result.hasErrors()) {
return "redirect:/";
}
tweetsService.createTweet(tweet);
return "redirect:/";
}
}
TweetsServiceImpl
#Service
#Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class TweetsServiceImpl implements TweetsService {
private TweetsRepository tweetsRepo;
#Autowired
private UserRepository userRepo;
#Autowired
public TweetsServiceImpl(UserRepository userRepo, TweetsRepository tweetsRepo) {
this.userRepo = userRepo;
this.tweetsRepo = tweetsRepo;
}
public TweetsRepository getTweetsRepo() {
return tweetsRepo;
}
public void setTweetsRepo(TweetsRepository tweetsRepo) {
this.tweetsRepo = tweetsRepo;
}
public UserRepository getUserRepo() {
return userRepo;
}
public void setUserRepo(UserRepository userRepo) {
this.userRepo = userRepo;
}
public List<Tweets> findAll() {
return tweetsRepo.findAll();
}
#Override
#Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public void createTweet(CreateTweet createTweet) {
Tweets tweet = new Tweets();
tweet.setTweet(createTweet.getTweet());
tweet.setUser(createTweet.getUser());
tweetsRepo.save(tweet);
}
}
CreateTweet
public class CreateTweet {
#NotNull
#Size(min=1, max=500)
private String tweet;
#NotNull
private User user;
public String getTweet() {
return tweet;
}
public void setTweet(String tweet) {
this.tweet = tweet;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
User class
#Entity
#Table(name = "usr", indexes = { #Index(columnList = "email", unique = true) })
// using usr because in may conflict with the name of the class
public class User {
public static final int EMAIL_MAX = 250;
public static final int NAME_MAX = 50;
/*
* public static enum Role {
*
* UNVERIFIED, BLOCKED, ADMINISTRATOR
*
* }
*/
// primary key long, needs to be annotated with #Id
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
// add columns
#Column(nullable = false, length = EMAIL_MAX)
private String email;
#Column(nullable = false, length = NAME_MAX)
private String name;
// no length, the password will be encrypted to some longer value than the
// user enters
#Column(nullable = false)
private String password;
#OneToMany(mappedBy="user")
List<Tweets> tweets;
public List<Tweets> getTweets() {
return tweets;
}
public void setTweets(List<Tweets> tweets) {
this.tweets = tweets;
}
public void setUsername(String username) {
this.username = username;
}
#Column(nullable = false)
private String username;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isEditable() {
User loggedIn = MyTools.getSessionUser();
if (loggedIn == null) {
return false;
}
return loggedIn.getId() == id;
}
public String getUsername() {
return username;
}
}
How can I get the form to show on the page and users can post?
Your TweetsController has mistakes. The way you wroted it your #ModelAttribute construct method will be called before every request, always making a new instance.
To fix this, you should annotate your controller with #SessionAttributes("tweets"). This way when your construct method is called it will store the model attribute in the model but also in the session store as well. Also, whenever the "tweets" model attribute is accessed it will be looked up in the session. For this reason your construct method will be called only initially.
#SessionAttributes("tweets") will also ensure that the model variable always exists in the request and your error will be resolved.
A confusing bit is that sometimes you store a class Tweets and sometimes CreateTweet as a "tweets" model attribute. Anyways, the following controller should work for you
#SessionAttributes("tweets")
public class TweetsController {
private TweetsService tweetsService;
#ModelAttribute("tweets")
// name for tweet form in home public Tweets
public Tweets construct() {
return new Tweets();
}
// //----------------------------------------------------------------------
#RequestMapping(value = "/")
public String newTweet(Model model) {
model.addAttribute("tweets", new CreateTweet());
return "/home";
}
#RequestMapping(method = RequestMethod.POST)
public String tweet(#ModelAttribute("tweets") CreateTweet tweet, BindingResult result,
RedirectAttributes redirectAttributes) {
if (result.hasErrors()) {
return "redirect:/";
}
tweetsService.createTweet(tweet);
return "redirect:/";
}
}
I cannot get dbRef object from Mongo. In my entity package I have a User class with a Parent class inheriting.
Here is the User class:
public class User {
#Id
private ObjectId id;
#DBRef
private Account account;
private String name;
public String getId() {
if (id != null) {
return id.toStringMongod();
}
return null;//no id
}
public void setId(ObjectId objectId) {
this.id = objectId;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
}
As you can see above, I am putting an object of Account here.
My Parent class simply extends User:
#Document
public class Parent extends User {
#JsonProperty("is_activated")
private boolean isActivated;
public boolean isActivated() {
return isActivated;
}
public void setActivated(boolean isActivated) {
this.isActivated = isActivated;
}
}
Note: nothing magic with isActivated.
In my ParentDaoImpl class:
#Service
public class ParentDaoImpl extends AbstractDaoImpl implements ParentDao {
#Override
public Parent getParentByLogin(String login) {
Query query = new Query(Criteria.where("login").is(login));
return mongoOperations.findOne(query, Parent.class, "parents");
}
}
The problem is that if I call getParentByLogin method, it returns evertyning but Account field is null. Maybe findOne doesn't give dbRef inside. I think in relational Databases, there would be something like join. I want my method to give me account field as well.
Thanks for your help!
Can you try something like this.
....
#Field("fieldName")
#DBRef(collection = "mongoCollectionName")
private Account account;
....