Spring Security basic auth for sign in - spring-boot

I am new to springboot security.And i just find that it is quite hard to follow the latest version since some of the method has already outdated.So i just follow on some of the tutorials to work on the jwt and authentication with mysql.I have problem on the use of the basic auth for generating the token when it is integrated to my own model.Here are my code.
Tokenservice:
#Service
public class TokenService {
private final JwtEncoder encoder;
private PasswordEncoder passwordEncoder;
public TokenService(JwtEncoder jwtEncoder, PasswordEncoder passwordEncoder) {
this.encoder = jwtEncoder;
this.passwordEncoder = passwordEncoder;
}
#Autowired
private JpaUserrepository jpaUserrepository;
private Authentication auth;
public String generateToken (Authentication authentication){
Instant now=Instant.now();
String scope=authentication.getAuthorities().stream() //Stream<capture of ? extends GrantedAuthority >
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(" "));
JwtClaimsSet claims = JwtClaimsSet.builder()
.issuer(authentication.getName())
.issuedAt(now)
.expiresAt(now.plus(1, ChronoUnit.HOURS))
.claim("scope",scope).build();
return this.encoder.encode(JwtEncoderParameters.from((claims))).getTokenValue();
}
public String signup(JpaUser jpaUser) {
System.out.println(jpaUserrepository.findByUsername(jpaUser.getUsername()));
if(jpaUserrepository.findByUsername(jpaUser.getUsername()).isPresent())
{return "repeated username";}
jpaUserrepository.save(new JpaUser(jpaUser.getUsername(),passwordEncoder.encode(jpaUser.getPassword()),jpaUser.getEmail(),jpaUser.getRoles()));
return "sign up success";
}
}
I want to sign up which can return the token,but the required type of generatedtoken method is authentication (Basic Auth) but i have no idea to convert my Jpauser model to authentication interphase.
Here is Jpauser model:
#Entity
#Table(name = "JpaUser")
public class JpaUser {
#Id #GeneratedValue
private Long id;
private String username;
private String password;
private String email;
private String roles;
public JpaUser() {}
public JpaUser(String username, String password,String email, String roles) {
this.username = username;
this.password = password;
this.email=email;
this.roles = roles;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public void setPassword(String password) {
this.password = password;
}
public String getRoles() {
return roles;
}
public void setRoles(String roles) {
this.roles = roles;
}
#Override
public String toString() {
return "SecurityUser{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", email='" + email + '\'' +
", roles='" + roles + '\'' +
'}';
}
}
My securityconfig:
#Bean
public SecurityFilterChain securityfilterchain(HttpSecurity http) throws Exception {
return http
//if used csrf.ignoringAntMatchers -->prevent the attack from cross-origin
//.csrf(csrf -> csrf.disable())
.csrf(csrf -> csrf.ignoringAntMatchers("/shownews/**","/getnews/**","/token","/signup"))
.authorizeRequests(auth-> auth
.antMatchers("/shownews/**").permitAll()
.antMatchers("/getnews/**").permitAll()
.anyRequest().authenticated())
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
//Link to the jpauserservice to check whether the authentication valid (similar to authentication manager)
.userDetailsService(myUserDetailsService)
.headers(headers -> headers.frameOptions().sameOrigin())
.httpBasic(Customizer.withDefaults())
.formLogin().and()
.build();
}
#Bean
JwtDecoder jwtDecoder(){
return NimbusJwtDecoder.withPublicKey(rsakeys.publicKey()).build();
}
In fact, i am quite loss when i learn this topic since i think the doc is quite hard to understand .I am just wondering if there any materials that are more easy to understand amd modifymy code?

Related

How to send mail using spring boot?

i'm trying to sent mail in my spring boot application using mailtrap to test that and this is my code:
pom.xml :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
application.properties: i took this credentials from my account on mailtrap.io :
spring.mail.host=smtp.mailtrap.io
spring.mail.port=2525
spring.mail.username=2d9a7d89fcc8f8
spring.mail.password=9bb8e9090abd96
EmailCfg :
#Component
public class EmailCfg {
#Value("${spring.mail.host}")
private String host;
#Value("${spring.mail.port}")
private int port;
#Value("${spring.mail.username}")
private String username;
#Value("${spring.mail.password}")
private String password;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
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;
}
}
EmailMsg :
public class EmailMsg {
#NotNull
private String name;
#NotNull
#Email
private String email;
#NotNull
#Min(10)
private String feedback;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getFeedback() {
return feedback;
}
public void setFeedback(String feedback) {
this.feedback = feedback;
}
}
Controller :
#CrossOrigin(origins = StringsConstants.FRONT_BASE_URL, maxAge = 3600)
#Api("Events Controller")
#RestController
#RequestMapping(StringsConstants.EVENTS_URL)
public class EventsController {
#Autowired
private EmailCfg emailCfg;
#PostMapping(value = "/sendMail")
#PreAuthorize("hasRole('USER')")
public void sendFeedback(#RequestBody EmailMsg feedback,
BindingResult bindingResult){
if(bindingResult.hasErrors()){
throw new ValidationException("Feedback is not valid");
}
// Create a mail sender
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost(this.emailCfg.getHost());
mailSender.setPort(this.emailCfg.getPort());
mailSender.setUsername(this.emailCfg.getUsername());
mailSender.setPassword(this.emailCfg.getPassword());
// Create an email instance
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setFrom(feedback.getEmail());
mailMessage.setTo("rc#feedback.com");
mailMessage.setSubject("New feedback from " + feedback.getName());
mailMessage.setText(feedback.getFeedback());
// Send mail
mailSender.send(mailMessage);
}
}
It's not working and im not getting any error !!! on postman im getting this
{
"timestamp": "2021-04-11T09:52:43.286+0000",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/api/events/sendEmail"
}
any ideas? please !

Handling Authentication Failure with Springboot & Spring security

In a Rest appplication developped with Spring, I use POJO classes, DTO and entity for users management. Here is an abstract of my entity class.
#Entity
#Table(name="users")
#Getter #Setter
#AllArgsConstructor #NoArgsConstructor
public class UserEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false, unique = true)
private String userKeyId;
#Column(nullable = false, length = 50)
private String firstName;
#Column(nullable = false, length = 50)
private String lastName;
#Column(nullable = false, length = 120, unique = true)
private String email;
#Column(nullable = false)
private String encryptedPassword;
#Column
private String emailVerificationToken;
#Column(name = "email_verification_status", columnDefinition = "BOOLEAN NOT NULL DEFAULT FALSE")
private Boolean emailVerificationStatus = false;
#Column(name="is_account_non_expired")
private Boolean isAccountNonExpired;
#Column(name="is_account_non_locked")
private Boolean isAccountNonLocked;
#Column(name="is_credentials_non_expired")
private Boolean isCredentialsNonExpired;
#Column(name="is_enabled")
private Boolean isEnabled;
#Column(name="is_logged_in")
private Boolean isLoggedIn;
#ManyToMany(cascade= { CascadeType.PERSIST }, fetch = FetchType.EAGER )
#JoinTable(
name = "user_role",
joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns=#JoinColumn(name = "role_id", referencedColumnName = "id"))
private Collection<RoleEntity> roles;
#CreationTimestamp
#Temporal(TemporalType.DATE)
#Column(name="created_at")
private Date createdAt;
#UpdateTimestamp
#Temporal(TemporalType.DATE)
#Column(name="updated_at")
private Date updatedAt;
}
I have a UserServiceImpl class that implements UserDetails
I do have then to implement loadUserByUsername
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
UserEntity userEntity = userRepository.findByEmail(email);
if( userEntity == null) {
throw new UsernameNotFoundException("User email is not in the database");
} else {
validateLoginAttempt(userEntity);
log.info("Returning User : " + userEntity.getFirstName() + " " + userEntity.getLastName());
userEntity.setLastLoginDateDisplay(userEntity.getLastLoginDate());
userEntity.setLastLoginDate(new Date());
userRepository.save(userEntity);
return new UserPrincipal(userEntity);
}
}
If user exists I call a method to validate authentication.
private void validateLoginAttempt(UserEntity user) {
if(user.getIsAccountNonLocked()) {
if(loginAttemptService.hasExceededMaxAttempts(user.getEmail())) {
user.setIsAccountNonLocked(Boolean.FALSE);
} else {
user.setIsAccountNonLocked(Boolean.TRUE);
}
} else {
loginAttemptService.evictUserFromLoginAttemptCache(user.getEmail());
}
}
This method allows me to check if the user account is locked or not and if user tried to connect too many times.
My LoginAttemptServiceImpl is the following:
#Service
public class LoginAttemptServiceImpl implements LoginAttemptService {
public static final int MAXIMUM_AUTH_ATTEMPT = 5;
public static final int AUTH_ATTEMPT_INCREMENT = 1;
private LoadingCache<String, Integer> loginAttemptCache;
private String username;
public LoginAttemptServiceImpl() {
super();
loginAttemptCache = CacheBuilder.newBuilder()
.expireAfterWrite(15, TimeUnit.MINUTES)
.maximumSize(10000)
.build(new CacheLoader<>() {
#Override
public Integer load(String key) {
return 0;
}
});
}
#Override
public void evictUserFromLoginAttemptCache(String username) {
loginAttemptCache.invalidate(username);
}
#Override
public void addUserToLoginAttemptCache(String username) {
int attempts = 0;
try {
attempts = AUTH_ATTEMPT_INCREMENT + loginAttemptCache.get(username);
loginAttemptCache.put(username, attempts);
} catch (ExecutionException e) {
e.printStackTrace();
}
}
#Override
public boolean hasExceededMaxAttempts(String username) {
try {
return loginAttemptCache.get(username) >= MAXIMUM_AUTH_ATTEMPT;
} catch (ExecutionException e) {
e.printStackTrace();
}
return false;
}
#Override
public int getLoginAttempts(String username) throws ExecutionException {
return loginAttemptCache.get(username);
}
}
I also implemented an event listener for authentication failure:
#Component
public class AuthenticationFailureListener {
private final LoginAttemptService loginAttemptService;
#Autowired
public AuthenticationFailureListener(LoginAttemptService loginAttemptService) {
this.loginAttemptService = loginAttemptService;
}
#EventListener
public void onAuthenticationFailure(AuthenticationFailureBadCredentialsEvent event) {
Object principal = event.getAuthentication().getPrincipal();
if (principal instanceof String) {
String username = (String) event.getAuthentication().getPrincipal();
loginAttemptService.addUserToLoginAttemptCache(username);
}
}
}
And finally my AuthenticationFilter allows me to manage successful and unsuccessful response:
#Override
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain,
Authentication authResult) throws IOException, ServletException {
String userName = ((UserPrincipal)authResult.getPrincipal()).getUsername();
// built the token
String token = Jwts.builder()
.setSubject(userName)
.setExpiration(new Date(System.currentTimeMillis() + SecurityConstants.EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS512, SecurityConstants.getTokenSecret())
.compact();
UserService userService = (UserService) SpringApplicationContext.getBean("userServiceImpl");
UserDto userDto = userService.getUser(userName);
response.addHeader(SecurityConstants.HEADER_STRING_USERID, userDto.getUserKeyId());
response.addHeader(SecurityConstants.HEADER_STRING, SecurityConstants.TOKEN_PREFIX + token);
}
#SneakyThrows
#Override
protected void unsuccessfulAuthentication(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException failed) throws IOException, ServletException {
// super.unsuccessfulAuthentication(request, response, failed);
int attempts;
if(loginAttemptService.hasExceededMaxAttempts(this.username)) {
attempts = loginAttemptService.getLoginAttempts(this.username);
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Attempt number " + attempts + ": Account is locked for 15 minutes");
} else {
attempts = loginAttemptService.getLoginAttempts(this.username);
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Attempt number " + attempts + ": " + (SecurityConstants.MAX_AUTH_ATTEMPTS - attempts) + " - before account is blocked");
}
}
Authentication works when it's successful... My issue concerns failure and i have 3 issues:
I would like to return an object in case of failure. the response.sendError should do the job but it doesn't. I also tried to return a Json response : https://www.baeldung.com/servlet-json-response
I use Guava cache but I also update database at the same time by setting isAccountNonLocked to false. I'd like to set the value to True once the cache is cleared.
I do not update the count of attempt in unsuccessfulAuthentication method. My response is always : Attempt number 0: 5 - before account is blocked
Thanks for help and for reading the whole text!
Regarding issue number 1, you can use a similar approach as the one mentioned in the link you posted, but use response.getWriter().write(String) and Jackson's ObjectMapper, like this:
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
ObjectMapper mapper = new ObjectMapper();
response.getWriter().write(mapper.writeValueAsString( /*Your custom POJO here */ ));
For issue 2: I found a trick that solves it. Instead of updating the database at the same time i clear the cache, I make the update at login validation...
private void validateLoginAttempt(UserEntity user) {
if(user.getIsAccountNonLocked()) {
if(loginAttemptService.hasExceededMaxAttempts(user.getEmail())) {
user.setIsAccountNonLocked(Boolean.FALSE);
} else {
user.setIsAccountNonLocked(Boolean.TRUE);
}
} else {
if(!loginAttemptService.hasExceededMaxAttempts(user.getEmail())) {
user.setIsAccountNonLocked(Boolean.TRUE);
}
loginAttemptService.evictUserFromLoginAttemptCache(user.getEmail());
}
}
For issue 3:
In my WebSecurity class which extends WebSecurityConfigurerAdapter, I implemented a bean in order to inject it in my AuthenticationFilter.
Here is my bean:
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
Here is my AuthenticationFilter class. I initially added this class as component (bad idea which generated error messages).
// #Component
public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final AuthenticationManager authenticationManager;
private final LoginAttemptService loginAttemptService;
private String username;
public AuthenticationFilter(AuthenticationManager authenticationManager, LoginAttemptService loginAttemptService) {
this.authenticationManager = authenticationManager;
this.loginAttemptService = loginAttemptService;
}
....

Spring Boot; passing user's First Name to welcome.jsp after logging in

A lot of the articles online for Spring Boot deals with Spring Security and it does not help me in the slightest. I am trying to implement a registration and login page and once the user successfully logins, it will take them to a welcome page where it should display their first name, something like "Welcome first name or Welcome username". I have tried passing the first name through a
model.addAttribute("firstName", accountInstance.getFirstName());
but that doesn't seem to work. Any hints to achieve this would be much appreciated
Login Controller
#Controller
public class LoginController {
#Autowired
private AccountRepository accountRepo;
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String showLoginPage(ModelMap model) {
model.addAttribute("login", new AccountEntity());
return "login";
}
#RequestMapping(value = "/login", method = RequestMethod.POST)
public Object submitLoginIn(#ModelAttribute("login") AccountEntity accountForm, Model model) {
AccountEntity accountInstance = accountRepo.findByEmail(accountForm.getEmail().toLowerCase());
// Password Verifier using Argon2
Argon2PasswordEncoder argon2PasswordEncoder = new Argon2PasswordEncoder();
boolean passwordMatch = argon2PasswordEncoder.matches(accountForm.getPassword(), accountInstance.getPassword());
// issue where if i use caps email, throws null pointer exception
if (accountInstance == null || !passwordMatch) {
System.out.println("Invalid Email or Password");
// return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
return "login";
} else if (accountInstance.isEnabled() == false) {
System.out.println("Cant login cause not verified");
return "login";
} else {
System.out.println("account exist");
model.addAttribute("firstName", accountInstance.getFirstName());
return "redirect:welcome"; // Change later
}
}
}
Account Repository
public interface AccountRepository extends CrudRepository<AccountEntity, Long> {
// Optional<AccountEntity> findById(Long Id);
AccountEntity findByUserName(String userName);
AccountEntity findByPassword(String password);
AccountEntity findByEmail(String email);
AccountEntity findByVerificationCode(String verificationCode);
}
Account Entity
#Entity(name = "user")
public class AccountEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
private String userName;
private String email;
private String password;
// private String gender;
private Integer age;
private Date createdDate;
private boolean enabled;
#Column(updatable = false)
private String verificationCode;
// Getters and Setters
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
/*
* public String getGender() { return gender; }
*
* public void setGender(String gender) { this.gender = gender; }
*/
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getVerificationCode() {
return verificationCode;
}
public void setVerificationCode(String verificationCode) {
this.verificationCode = verificationCode;
}
public Date getCreatedDate() {
return createdDate;
}
public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
Welcome.jsp
<p> Welcome, ${firstName.firstName} </p>
<!-- <p> Welcome, ${firstName} </p> -->
SO #Bollywood was correct with the redirecting:welcome. Doing so didn't pass the value I wanted to the jsp. Changing it to return "welcome" instead of return "redirect:welcome" worked!

Spring Data: Could not determine type for: java.util.List, at table: user, for columns: [org.hibernate.mapping.Column(roles)]

I am new to Spring, and I was following this tutorial Spring Rest Services
to understand how oAuth works with REST APIs.
Prior to this, my app was running smoothly.
While working with the tutorial, it required me to have my User entity implement UserDetails. And I had to add an extra List<String> roles because it is used in my UserDetailsImpl service which implements UserDetailsService.
And now when I run mvn spring-boot:run I get the error that's mentioned in the title.
I looked up online, but most of the issues were related to table associations via a particular column, but in my code, there is no type of association mapped to/from roles column.
Here is my User entity:
#Entity
public class User implements UserDetails {
#Id
private UUID id;
private String name;
private String email;
private String password;
private List<String> roles;
public User (){
}
public User (String email, String name, String password, UUID id, List<String> roles){
this.email = email;
this.name = name;
this.password = password;
this.id = id;
this.roles = roles;
}
public String getEmail() {
return email;
}
public String getName() {
return name;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
#Override
public String getPassword() {
return password;
}
#Override
public String getUsername() {
return email;
}
#Override
public boolean isAccountNonExpired() {
return false;
}
#Override
public boolean isAccountNonLocked() {
return false;
}
#Override
public boolean isCredentialsNonExpired() {
return false;
}
#Override
public boolean isEnabled() {
return false;
}
public UUID getId() {
return id;
}
List<String> getRoles() {
return roles;
}
public void setPassword(String password) {
this.password = password;
}
public void setEmail(String email) {
this.email = email;
}
public void setName(String name) {
this.name = name;
}
public void setId(UUID id) {
this.id = id;
}
}
And this my UserDetailsImp service:
#Service
public class UserDetailsImp implements UserDetailsService {
#Autowired
UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.getOneByEmail(email);
UserBuilder builder = null;
if( user != null){
builder.username(user.getEmail()).password(user.getPassword()).roles(String.join("",user.getRoles()));
} else {
throw new UsernameNotFoundException("User not found");
}
return builder.build();
}
}
Any help would be hugely appreciated.
The field private List<String> roles has unknown type in the DB.
Try using #ElementCollection annotation.
https://docs.oracle.com/javaee/6/api/javax/persistence/ElementCollection.html

Empty field Data Type in springfox swagger ui

I have a Spring Web MVC application with rest services and I try to use Springfox for automated docs for it.
I use
io.springfox:springfox-swagger2:2.5.0
io.springfox:springfox-swagger-ui:2.5.0
org.webjars:swagger-ui:2.1.4
My SwaggerConfig:
#Configuration
#EnableSwagger2
#Profile("dev")
public class SwaggerConfig {
#Bean
public Docket api() {
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build().apiInfo(apiInfo());
return docket;
}
}
And:
#Configuration
#EnableWebMvc
#Profile("dev")
public class SwaggerWebMvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
I have a rest controller:
#Api
#RestController
#RequestMapping(RegistrationRestController.ROOT_PATH)
public class RegistrationRestController {
private final static Logger log = LogManager.getLogger(RegistrationRestController.class);
public static final String ROOT_PATH = "/rest/registration";
private final ResponseUtil responseUtil;
private final UserService userService;
#Autowired
public RegistrationRestController(ResponseUtil responseUtil, UserService userService) {
log.debug("Instantiate RegistrationRestController bean");
this.responseUtil = Objects.requireNonNull(responseUtil);
this.userService = Objects.requireNonNull(userService);
}
#RequestMapping(value = {""}, method = RequestMethod.POST)
#ApiResponses({
#ApiResponse(code = 200, message = "Create new user and authorize them. Returns access token", response = AccessTokenDTO.class)
})
#ApiOperation(value = "Create new user", response = AccessTokenDTO.class)
public ResponseDTO newUserRegistration(#Valid #ApiParam(required = true) RegistrationDTO registrationDTO) {
log.debug("POST {} with registrationDTO='{}'", ROOT_PATH, registrationDTO.toString());
AccessTokenDTO accessToken = userService.createUserAndAuthorize(registrationDTO);
return responseUtil.wrapResult(accessToken);
}
}
And RegistrationDTO:
#ApiModel
public class RegistrationDTO {
#NotNull(message = "registrationDTO.phone.notNull.fail")
#Pattern(regexp = "[0-9]{10}", message = "registrationDTO.phone.pattern.fail")
private String phone;
#NotNull(message = "registrationDTO.email.notNull.fail")
#Email(message = "registrationDTO.email.pattern.fail")
private String email;
#NotNull(message = "registrationDTO.lastName.notNull.fail")
#Size(min = 1, message = "registrationDTO.lastName.size.fail")
private String lastName;
#NotNull(message = "registrationDTO.firstName.notNull.fail")
#Size(min = 1, message = "registrationDTO.firstName.size.fail")
private String firstName;
#NotNull(message = "registrationDTO.password.notNull.fail")
#Size(min = 6, message = "registrationDTO.password.size.fail")
private String password;
#NotNull(message = "registrationDTO.passwordConfirmation.notNull.fail")
#Size(min = 6, message = "registrationDTO.passwordConfirmation.size.fail")
private String passwordConfirmation;
#AssertTrue(message = "registrationDTO.isPasswordMatch.fail")
public boolean isPasswordMatch() {
return Objects.equals(password, passwordConfirmation);
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPasswordConfirmation() {
return passwordConfirmation;
}
public void setPasswordConfirmation(String passwordConfirmation) {
this.passwordConfirmation = passwordConfirmation;
}
#Override
public String toString() {
return "RegistrationDTO{" +
"phone='" + phone + '\'' +
", email='" + email + '\'' +
", lastName='" + lastName + '\'' +
", firstName='" + firstName + '\'' +
'}';
}
}
But when I'm opening localhost:8080/swagger-ui.html I see an empty Data type for RegistrationDTO parameter.
What I'm doing wrong? :(
Need to specify #RequestBody before method parameter

Resources