Commit ef7e5aee by Ninh Hoang Cuong

exception handle

parent 741223c3
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
<properties> <properties>
<java.version>1.8</java.version> <java.version>1.8</java.version>
<open-api.version>1.1.49</open-api.version>
</properties> </properties>
<dependencies> <dependencies>
...@@ -49,20 +50,32 @@ ...@@ -49,20 +50,32 @@
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>io.jsonwebtoken</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>jjwt</artifactId>
<scope>test</scope> <version>0.9.1</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-core</artifactId>
<version>${open-api.version}</version>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>org.junit.vintage</groupId> <groupId>io.github.classgraph</groupId>
<artifactId>junit-vintage-engine</artifactId> <artifactId>classgraph</artifactId>
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-ui -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>${open-api.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.security</groupId> <groupId>io.github.classgraph</groupId>
<artifactId>spring-security-test</artifactId> <artifactId>classgraph</artifactId>
<scope>test</scope> <version>4.8.44</version>
</dependency> </dependency>
</dependencies> </dependencies>
......
...@@ -2,12 +2,14 @@ package com.feedback.demo; ...@@ -2,12 +2,14 @@ package com.feedback.demo;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@SpringBootApplication @SpringBootApplication
public class DemoApplication { @EnableJpaAuditing
public class Application {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args); SpringApplication.run(Application.class, args);
} }
} }
package com.feedback.demo.config;
import com.feedback.demo.entities.User;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.Collections;
@Data
public class CustomUserDetail implements UserDetails {
User user;
public CustomUserDetail(User user) {
this.user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.singleton(new SimpleGrantedAuthority("ROLE_USER"));
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
package com.feedback.demo.config;
import com.feedback.demo.entities.User;
import com.feedback.demo.service.JwtService;
import com.feedback.demo.service.UserDetailServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtService jwtService;
@Autowired
UserDetailServiceImpl userDetailService;
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain)
throws ServletException, IOException {
String jwt = getJwtFromRequest(httpServletRequest);
try {
if (StringUtils.hasText(jwt)) {
User user = jwtService.getUserFromToken(jwt);
if (user == null) throw new RuntimeException("API not found or invalid");
UserDetails userDetails = new CustomUserDetail(user);
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(userDetails,
null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
} catch (Exception e) {
e.printStackTrace();
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
private String getJwtFromRequest(HttpServletRequest request) {
String authorization = request.getHeader("Authorization");
if (StringUtils.hasText(authorization) && authorization.startsWith("Bearer ")) {
return authorization.substring(7);
}
return null;
}
}
package com.feedback.demo.config;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.servers.Server;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
@Configuration
public class OpenAPIConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.servers(
Arrays.asList(
new Server().url("http://localhost:8080"),
new Server().url("https://user.loda.me")
)
)
.info(new Info().title("Cotam Application API")
.description("Sample Open API 3")
.contact(new Contact()
.name("Ninh Hoang Cuong")
.email("ninhhoangcuongtnnd15@gmail.com")
.url("https://facebook.com")
)
.license(new License()
.name("Apache 2.0")
.url("http://www.apache.org/licenses/LICENSE-2.0.html")
)
.version("1.0.0")
);
}
}
package com.feedback.demo.config;
import com.feedback.demo.service.UserDetailServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailServiceImpl userDetailService;
@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable();
http.authorizeRequests().antMatchers("/feedback-settings/**").permitAll().anyRequest().permitAll();
// http.authorizeRequests().antMatchers("/admin/**").hasAuthority("admin");
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
// http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
}
package com.feedback.demo.controllers;
import com.feedback.demo.dto.FeedBackSettingsDTO;
import com.feedback.demo.entities.FeedBackSettings;
import com.feedback.demo.repositories.UserRepository;
import com.feedback.demo.service.FeedBackSettingsService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@RestController
@RequestMapping("/feedback-settings")
@Tag(name = "Feed Back Settings")
public class FeedBackSettingsController {
@Autowired
private FeedBackSettingsService feedBackSettingsService;
@Autowired
private UserRepository userRepository;
@Operation(description = "Update FeedBack settings", responses = {
@ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = FeedBackSettings.class))), responseCode = "200")
})
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Thành công"),
@ApiResponse(responseCode = "404", description = "Không tìm thấy"),
@ApiResponse(responseCode = "401", description = "Chưa xác thực"),
@ApiResponse(responseCode = "403", description = "Truy cập bị cấm"),
})
@PostMapping("/update")
public ResponseEntity<FeedBackSettingsDTO> addFeedbackSettings(@Valid @RequestBody FeedBackSettingsDTO feedBackSettingsDTO){
return ResponseEntity.ok(feedBackSettingsService.updateSettings(feedBackSettingsDTO));
}
@Operation(description = "Get FeedBack settings", responses = {
@ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = FeedBackSettings.class))), responseCode = "200")
})
@GetMapping("/")
public ResponseEntity<FeedBackSettingsDTO> getFeedbackSettings(){
return ResponseEntity.ok(feedBackSettingsService.getFeedbackSettings());
}
}
package com.feedback.demo.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ChangePasswordRequest {
@NotBlank(message = "Password not Empty !")
@Size(min = 6, max = 32, message = "Choose a password 6–32 characters long." +
"Your password can be any combination of letters, numbers")
private String oldPass;
@NotBlank(message = "Password Not Empty !")
@Size(min = 6, max = 32, message = "Choose a password 6–32 characters long." +
"Your password can be any combination of letters, numbers")
private String newPass;
}
package com.feedback.demo.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class FeedBackDTO {
private Long id;
@NotBlank(message = "FullName required")
private String fullName;
@NotBlank(message = "AppName required")
private String appName;
private String url;
@Email(message = "Invalid email format")
@NotBlank(message = "Email required")
private String email;
private String phone;
private String type;
private String content;
private String imageUrl;
private Date createDate;
private Date updateDate;
}
package com.feedback.demo.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class FeedBackOptionsDTO {
private Long id;
private String optionValue;
private Integer optionOrder;
}
package com.feedback.demo.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class FeedBackSettingsDTO {
private Long id;
@NotNull
private Integer position;
private String iconURL;
@NotBlank
private String feedbackTitle;
@NotBlank
private String titleFullName;
@NotBlank
private String titleEmail;
@NotBlank
private String titlePhoneNumber;
@NotBlank
private String titleOptions;
@NotBlank
private String titleDescription;
private Date createDate;
private Date updateDate;
}
package com.feedback.demo.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class LoginRequest {
@Size(min = 3, max = 32, message = "Choose a username 2–32 characters long. " +
"Your username can be any combination of letters, numbers")
@NotBlank(message = "Username not Empty !")
private String username;
@Size(min = 6, max = 32, message = "Choose a password 6–32 characters long." +
"Your password can be any combination of letters, numbers")
@NotBlank(message = "Password not Empty !")
private String password;
}
package com.feedback.demo.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class LoginResponse {
private Long id;
private String username;
private String token;
}
package com.feedback.demo.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Payload {
private int sub, iat, exp;
}
package com.feedback.demo.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class SignupRequest {
@NotBlank(message = "Username not Empty !")
@Size(min = 6, max = 32, message = "Choose a username 6–32 characters long. " +
"Your username can be any combination of letters, numbers")
private String username;
@NotBlank(message = "Password Not Empty")
@Size(min = 6, max = 32, message = "Choose a password 6–32 characters long. " +
"Your password can be any combination of letters, numbers")
private String password;
@NotBlank(message = "Email required")
@Email(message = "Invalid email format")
private String email;
private String phone;
private String domain;
}
package com.feedback.demo.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserDTO {
private Long id;
@NotNull(message = "Username required")
private String username;
@NotNull(message = "Password required")
private String password;
@NotBlank(message = "Email required")
@Email(message = "Invalid email format")
private String email;
private String phone;
private String domain;
private String description;
@NotBlank(message = "AppKey required")
private String appKey;
@NotBlank(message = "AppSecret required")
private String appSecret;
private Date createDate;
private Date updateDate;
private List<FeedBackDTO> feedBacks = new ArrayList<>();
private FeedBackOptionsDTO feedBackOptions;
private FeedBackSettingsDTO feedBackSettings;
}
package com.feedback.demo.entities;
import lombok.*;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.util.Date;
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@EntityListeners(AuditingEntityListener.class)
public class FeedBack {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 2000)
private String fullName;
@Column(length = 2000)
private String appName;
@Column(length = 2000)
private String url;
@Column(length = 100)
private String email;
@Column(length = 20)
private String phone;
@Column(length = 5)
private String type;
@Column(columnDefinition = "TEXT")
private String content;
@Column(name = "image_url")
private String imageUrl;
@CreatedDate
@Column(name = "create_date")
private Date createDate;
@LastModifiedDate
@Column(name ="last_modified_date")
private Date updateDate;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
package com.feedback.demo.entities;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import javax.persistence.*;
import java.util.Date;
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Table
public class FeedBackOptions {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 200,name = "option_value")
private String optionValue;
@Column(name = "option_order")
private Integer optionOrder;
@CreatedDate
@Column(name = "create_date")
private Date createDate;
@LastModifiedDate
@Column(name ="last_modified_date")
private Date updateDate;
@JsonIgnore
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
}
package com.feedback.demo.entities;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.*;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.util.Date;
@Entity
@Table
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@EntityListeners(AuditingEntityListener.class)
@ToString(exclude = "user")
public class FeedBackSettings {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Integer position;
@Column(name = "icon_url")
private String iconURL;
private String feedbackTitle;
private String titleFullName;
private String titleEmail;
private String titlePhoneNumber;
private String titleOptions;
private String titleDescription;
@CreatedDate
@Column(name = "create_date")
private Date createDate;
@LastModifiedDate
@Column(name ="last_modified_date")
private Date updateDate;
@JsonIgnore
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
}
package com.feedback.demo.entities;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.*;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@EntityListeners(AuditingEntityListener.class)
@Table(name = "userr")
@ToString(exclude = {"feedBacks"})
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
@Column(unique = true)
private String username;
@NotNull
@Column(unique = true)
private String password;
@Column(unique = true,length = 300)
private String email;
@Column(length = 20)
private String phone;
@Column(length = 200)
private String domain;
@Column(length = 2000)
private String description;
@Column(length = 200)
private String appKey;
@Column(length =200)
private String appSecret;
@CreatedDate
private Date createDate;
@LastModifiedDate
private Date updateDate;
@OneToMany(mappedBy ="user",fetch = FetchType.LAZY)
private List<FeedBack> feedBacks = new ArrayList<>();
@OneToOne(mappedBy = "user",cascade = CascadeType.ALL,fetch = FetchType.LAZY,optional = false)
private FeedBackOptions feedBackOptions;
@OneToOne(mappedBy = "user",cascade = CascadeType.ALL,fetch = FetchType.LAZY,optional = false)
private FeedBackSettings feedBackSettings;
}
package com.feedback.demo.exceptionhandle;
public class ApiMissingException extends RuntimeException {
private static final long serialVersionUID = 1L;
public ApiMissingException() {
super("API key is missing or invalid");
}
}
package com.feedback.demo.exceptionhandle;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
@ControllerAdvice
@RestController
public class CustomResponseException extends ResponseEntityExceptionHandler {
@ExceptionHandler(Exception.class)
public final ResponseEntity<Object> handlerAllException(Exception ex, WebRequest webRequest) {
ExceptionResponse<String> exceptionResponse = new ExceptionResponse<>(
HttpStatus.INTERNAL_SERVER_ERROR.value(), ex.getMessage());
return new ResponseEntity<>(exceptionResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
List<HashMap<String, String>> message = convertToMessage(ex.getBindingResult().getFieldErrors());
ExceptionResponse<List<HashMap<String, String>>> exceptionResponse = new ExceptionResponse<>(HttpStatus.BAD_REQUEST.value(), message);
return new ResponseEntity<>(exceptionResponse, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(UsernameIsAlreadyTakenException.class)
public final ResponseEntity<Object> handlerUsernameIsAlreadyTakenException(
UsernameIsAlreadyTakenException ex, WebRequest webRequest) {
ExceptionResponse<String> exceptionResponse = new ExceptionResponse<>(HttpStatus.CONFLICT.value(), ex.getMessage());
return new ResponseEntity<>(exceptionResponse, HttpStatus.CONFLICT);
}
@ExceptionHandler(BadCredentialsException.class)
public final ResponseEntity<Object> handlerUnAuthorizedException(Exception ex, WebRequest webRequest) {
ExceptionResponse<String> exceptionResponse = new ExceptionResponse<>(HttpStatus.UNAUTHORIZED.value(),
"UnAuthorized , Username or Password incorrectly !");
return new ResponseEntity<>(exceptionResponse, HttpStatus.UNAUTHORIZED);
}
@ExceptionHandler(PasswordNotMatchException.class)
public final ResponseEntity<Object> handlePassWordNotMatchException(PasswordNotMatchException ex,
WebRequest webRequest) {
ExceptionResponse<String> exceptionResponse = new ExceptionResponse<>(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
return new ResponseEntity<>(exceptionResponse, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(ApiMissingException.class)
public final ResponseEntity<Object> handleApiMissingException(ApiMissingException ex,
WebRequest webRequest) {
ExceptionResponse<String> exceptionResponse = new ExceptionResponse<>(HttpStatus.UNAUTHORIZED.value(), ex.getMessage());
return new ResponseEntity<>(exceptionResponse, HttpStatus.UNAUTHORIZED);
}
@ExceptionHandler(InternalAuthenticationServiceException.class)
public final ResponseEntity<Object> handleInternalAuthenticationServiceException(
InternalAuthenticationServiceException ex, WebRequest webRequest) {
ExceptionResponse<String> exceptionResponse = new ExceptionResponse<>(HttpStatus.UNAUTHORIZED.value(),
"UnAuthorized , Username or Password incorrectly");
return new ResponseEntity<>(exceptionResponse, HttpStatus.UNAUTHORIZED);
}
public List<HashMap<String, String>> convertToMessage(List<FieldError> fieldErrors) {
return fieldErrors.stream().map(fieldError -> {
HashMap<String, String> temp = new HashMap<>();
temp.put("key", fieldError.getField());
temp.put("value", fieldError.getDefaultMessage());
return temp;
}).collect(Collectors.toList());
}
}
package com.feedback.demo.exceptionhandle;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ExceptionResponse<T> {
int statusCode;
T message;
}
package com.feedback.demo.exceptionhandle;
public class PasswordNotMatchException extends RuntimeException {
private static final long serialVersionUID = 1L;
public PasswordNotMatchException() {
super("Current Password Not Match or new Password invalid");
}
}
package com.feedback.demo.exceptionhandle;
public class UsernameIsAlreadyTakenException extends RuntimeException{
public static final long serialVersionUID = 1L;
public UsernameIsAlreadyTakenException() {
super("Username is already taken");
}
}
package com.feedback.demo.mappers;
import com.feedback.demo.dto.FeedBackSettingsDTO;
import com.feedback.demo.entities.FeedBackSettings;
import com.feedback.demo.entities.User;
public class FeedBackSettingsMapper {
public static FeedBackSettings toEntity(FeedBackSettingsDTO feedBackSettingsDTO,Long userId){
return FeedBackSettings.builder()
.id(feedBackSettingsDTO.getId())
.position(feedBackSettingsDTO.getPosition())
.iconURL(feedBackSettingsDTO.getIconURL())
.feedbackTitle(feedBackSettingsDTO.getFeedbackTitle())
.titleDescription(feedBackSettingsDTO.getTitleDescription())
.titleEmail(feedBackSettingsDTO.getTitleEmail())
.titleFullName(feedBackSettingsDTO.getTitleFullName())
.titleOptions(feedBackSettingsDTO.getTitleOptions())
.titlePhoneNumber(feedBackSettingsDTO.getTitlePhoneNumber())
.createDate(feedBackSettingsDTO.getCreateDate())
.updateDate(feedBackSettingsDTO.getUpdateDate())
.user(
User.builder()
.id(userId)
.build()
)
.build();
}
public static FeedBackSettingsDTO toDTO(FeedBackSettings feedBackSettings){
return FeedBackSettingsDTO.builder()
.id(feedBackSettings.getId())
.position(feedBackSettings.getPosition())
.iconURL(feedBackSettings.getIconURL())
.feedbackTitle(feedBackSettings.getFeedbackTitle())
.titleDescription(feedBackSettings.getTitleDescription())
.titleEmail(feedBackSettings.getTitleEmail())
.titleFullName(feedBackSettings.getTitleFullName())
.titleOptions(feedBackSettings.getTitleOptions())
.titlePhoneNumber(feedBackSettings.getTitlePhoneNumber())
.createDate(feedBackSettings.getCreateDate())
.updateDate(feedBackSettings.getUpdateDate())
.build();
}
}
package com.feedback.demo.repositories;
import com.feedback.demo.entities.FeedBackOptions;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface FeedBackOptionsRepository extends JpaRepository<FeedBackOptions,Long> {
}
package com.feedback.demo.repositories;
import com.feedback.demo.entities.FeedBack;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface FeedBackRepository extends JpaRepository<FeedBack,Long> {
}
package com.feedback.demo.repositories;
import com.feedback.demo.entities.FeedBackSettings;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface FeedBackSettingsRepository extends JpaRepository<FeedBackSettings,Long> {
FeedBackSettings findByUserId(Long userId);
}
package com.feedback.demo.repositories;
import com.feedback.demo.entities.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User,Long> {
User findByUsername(String username);
}
package com.feedback.demo.service;
import com.feedback.demo.dto.FeedBackSettingsDTO;
import com.feedback.demo.entities.FeedBackSettings;
import com.feedback.demo.entities.User;
import com.feedback.demo.mappers.FeedBackSettingsMapper;
import com.feedback.demo.repositories.FeedBackSettingsRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class FeedBackSettingsService {
@Autowired
private FeedBackSettingsRepository feedBackSettingsRepository;
@Autowired
private UserService userService;
public FeedBackSettingsDTO updateSettings(FeedBackSettingsDTO feedBackSettingsDTO){
User user = userService.getCurrentUser();
FeedBackSettings settings = feedBackSettingsRepository.findByUserId(user.getId());
if (settings==null){
throw new RuntimeException("setting not available ! ");
}
settings.setPosition(feedBackSettingsDTO.getPosition());
settings.setIconURL(feedBackSettingsDTO.getIconURL());
settings.setFeedbackTitle(feedBackSettingsDTO.getFeedbackTitle());
settings.setTitleFullName(feedBackSettingsDTO.getTitleFullName());
settings.setTitleEmail(feedBackSettingsDTO.getTitleEmail());
settings.setTitlePhoneNumber(feedBackSettingsDTO.getTitlePhoneNumber());
settings.setTitleOptions(feedBackSettingsDTO.getTitleOptions());
settings.setTitleDescription(feedBackSettingsDTO.getTitleDescription());
return FeedBackSettingsMapper.toDTO(feedBackSettingsRepository.save(settings));
}
public FeedBackSettingsDTO getFeedbackSettings(){
User user = userService.getCurrentUser();
FeedBackSettings settings = feedBackSettingsRepository.findByUserId(user.getId());
if (settings==null){
throw new RuntimeException("setting not available ! ");
}
return FeedBackSettingsMapper.toDTO(settings);
}
}
package com.feedback.demo.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.feedback.demo.config.CustomUserDetail;
import com.feedback.demo.dto.Payload;
import com.feedback.demo.entities.User;
import com.feedback.demo.repositories.UserRepository;
import io.jsonwebtoken.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.Base64;
@Service
public class JwtService {
@Autowired
UserRepository userRepository;
public String generateToken(CustomUserDetail customUserDetail) {
return Jwts.builder().setSubject(Long.toString(customUserDetail.getUser().getId()))
.signWith(SignatureAlgorithm.HS256, customUserDetail.getUser().getPassword()).compact();
}
public User getUserFromToken(String token) throws IOException {
String[] part = token.split("\\.");
//lay cai payload ra
byte[] decodedBytes = Base64.getUrlDecoder().decode(part[1]);
String payload = new String(decodedBytes);
ObjectMapper mapper = new ObjectMapper();
Payload result = mapper.readValue(payload, Payload.class);
int id = result.getSub();
User user = userRepository.findById((long) id).orElse(null);
if (user != null) {
Claims claims = Jwts.parser().setSigningKey(user.getPassword()).parseClaimsJws(token).getBody();
return (Integer.parseInt(claims.getSubject()) == id && validateToken(token, user.getPassword())) ? user : null;
}
return null;
}
public boolean validateToken(String authToken, String secret) {
try {
Jwts.parser().setSigningKey(secret).parseClaimsJws(authToken);
return true;
} catch (ExpiredJwtException | UnsupportedJwtException
| MalformedJwtException | SignatureException | IllegalArgumentException e) {
e.printStackTrace();
}
return false;
}
}
package com.feedback.demo.service;
import com.feedback.demo.config.CustomUserDetail;
import com.feedback.demo.entities.User;
import com.feedback.demo.repositories.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service
public class UserDetailServiceImpl implements UserDetailsService {
@Autowired
UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new InternalAuthenticationServiceException("User not found !");
}
return new CustomUserDetail(user);
}
}
package com.feedback.demo.service;
import com.feedback.demo.config.CustomUserDetail;
import com.feedback.demo.dto.ChangePasswordRequest;
import com.feedback.demo.dto.LoginResponse;
import com.feedback.demo.dto.SignupRequest;
import com.feedback.demo.entities.User;
import com.feedback.demo.exceptionhandle.ApiMissingException;
import com.feedback.demo.exceptionhandle.UsernameIsAlreadyTakenException;
import com.feedback.demo.repositories.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtService jwtService;
public User login(String username, String password) {
Authentication authentication = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(username, password));
SecurityContextHolder.getContext().setAuthentication(authentication);
return getCurrentUser();
}
public User getCurrentUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication instanceof AnonymousAuthenticationToken) {
throw new ApiMissingException();
}
CustomUserDetail customUserDetail = (CustomUserDetail) authentication.getPrincipal();
return customUserDetail.getUser();
}
public LoginResponse checkToken(String token) throws IOException {
User user = jwtService.getUserFromToken(token);
if (user != null) {
String jwt = jwtService.generateToken(new CustomUserDetail(user));
return new LoginResponse(user.getId(), user.getUsername(), jwt);
} else {
throw new RuntimeException("Token is valid");
}
}
public LoginResponse getLoginResponse(String username, String password) {
User user = login(username, password);
String jwt = jwtService.generateToken(new CustomUserDetail(user));
return new LoginResponse(user.getId(), user.getUsername(), jwt);
}
public LoginResponse changePassword(ChangePasswordRequest changePasswordRequest) {
User user = getCurrentUser();
if (passwordEncoder.matches(changePasswordRequest.getOldPass(), user.getPassword())) {
user.setPassword(passwordEncoder.encode(changePasswordRequest.getNewPass()));
userRepository.save(user);
String jwt = jwtService.generateToken(new CustomUserDetail(user));
return new LoginResponse(user.getId(), user.getUsername(), jwt);
} else {
throw new RuntimeException("Old password not match !");
}
}
public LoginResponse signUp(SignupRequest signupRequest) {
User userCheck = userRepository.findByUsername(signupRequest.getUsername());
if (userCheck != null) {
throw new UsernameIsAlreadyTakenException();
}
userRepository.save(
User.builder()
.username(signupRequest.getUsername())
.password(
passwordEncoder.encode(signupRequest.getPassword())
)
.email(signupRequest.getEmail())
.phone(signupRequest.getPhone())
.domain(signupRequest.getDomain())
.build()
);
return getLoginResponse(signupRequest.getUsername(),signupRequest.getPassword());
}
}
server.port=8085
#------
spring.datasource.url=jdbc:mysql://localhost:3306/feedback?useSSL=false
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jackson.serialization.fail-on-empty-beans=false
package com.feedback.demo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class DemoApplicationTests {
@Test
void contextLoads() {
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment