refactoring
This commit is contained in:
@@ -1 +1,5 @@
|
||||
# spring-boot-webflux-jjwt
|
||||
Example Spring Boot and WebFlux (Reactive Web) with Spring Security and JWT for token Authentication and Authorization
|
||||
|
||||
### Documantation
|
||||
You can se my Medium story, [Authentication and Authorization Using JWT on Spring Webflux](https://medium.com/@ard333/29b81f813e78)
|
||||
2
pom.xml
2
pom.xml
@@ -3,7 +3,7 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>id.web.ard</groupId>
|
||||
<groupId>com.ard333</groupId>
|
||||
<artifactId>spring-boot-webflux-jjwt</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package id.web.ard.springbootwebfluxjjwt;
|
||||
package com.ard333.springbootwebfluxjjwt;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
@@ -1,8 +1,4 @@
|
||||
/*
|
||||
* Ardiansyah | http://ard.web.id
|
||||
*
|
||||
*/
|
||||
package id.web.ard.springbootwebfluxjjwt.model;
|
||||
package com.ard333.springbootwebfluxjjwt.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
@@ -11,7 +7,7 @@ import lombok.ToString;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ardiansyah
|
||||
* @author ard333
|
||||
*/
|
||||
@Data @NoArgsConstructor @AllArgsConstructor @ToString
|
||||
public class Message {
|
||||
@@ -1,26 +1,23 @@
|
||||
/*
|
||||
* Ardiansyah | http://ard.web.id
|
||||
*
|
||||
*/
|
||||
package id.web.ard.springbootwebfluxjjwt.model;
|
||||
package com.ard333.springbootwebfluxjjwt.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import id.web.ard.springbootwebfluxjjwt.security.model.Role;
|
||||
import com.ard333.springbootwebfluxjjwt.security.model.Role;
|
||||
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.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ardiansyah
|
||||
* @author ard333
|
||||
*/
|
||||
@ToString @AllArgsConstructor @NoArgsConstructor
|
||||
public class User implements UserDetails {
|
||||
@@ -29,20 +26,21 @@ public class User implements UserDetails {
|
||||
|
||||
private String password;
|
||||
|
||||
@Getter @Setter
|
||||
private Boolean enabled;
|
||||
|
||||
@Getter @Setter
|
||||
private List<Role> roles;
|
||||
|
||||
public User(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
//==============================
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return false;
|
||||
@@ -63,15 +61,10 @@ public class User implements UserDetails {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return this.roles.stream().map(authority -> new SimpleGrantedAuthority(authority.name())).collect(Collectors.toList());
|
||||
}
|
||||
//==============================
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
@@ -84,20 +77,4 @@ public class User implements UserDetails {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public Boolean getEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(Boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public List<Role> getRoles() {
|
||||
return roles;
|
||||
}
|
||||
|
||||
public void setRoles(List<Role> roles) {
|
||||
this.roles = roles;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,18 +1,13 @@
|
||||
/*
|
||||
* Ardiansyah | http://ard.web.id
|
||||
*
|
||||
*/
|
||||
package id.web.ard.springbootwebfluxjjwt.rest;
|
||||
package com.ard333.springbootwebfluxjjwt.rest;
|
||||
|
||||
import id.web.ard.springbootwebfluxjjwt.security.JWTUtil;
|
||||
import id.web.ard.springbootwebfluxjjwt.security.PBKDF2Encoder;
|
||||
import id.web.ard.springbootwebfluxjjwt.security.model.AuthRequest;
|
||||
import id.web.ard.springbootwebfluxjjwt.security.model.AuthResponse;
|
||||
import id.web.ard.springbootwebfluxjjwt.service.UserService;
|
||||
import com.ard333.springbootwebfluxjjwt.security.JWTUtil;
|
||||
import com.ard333.springbootwebfluxjjwt.security.PBKDF2Encoder;
|
||||
import com.ard333.springbootwebfluxjjwt.security.model.AuthRequest;
|
||||
import com.ard333.springbootwebfluxjjwt.security.model.AuthResponse;
|
||||
import com.ard333.springbootwebfluxjjwt.service.UserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
@@ -21,13 +16,13 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ardiansyah
|
||||
* @author ard333
|
||||
*/
|
||||
@RestController
|
||||
public class AuthenticationREST {
|
||||
|
||||
@Autowired
|
||||
private JWTUtil jwtTokenUtil;
|
||||
private JWTUtil jwtUtil;
|
||||
|
||||
@Autowired
|
||||
private PBKDF2Encoder passwordEncoder;
|
||||
@@ -39,7 +34,7 @@ public class AuthenticationREST {
|
||||
public Mono<ResponseEntity<AuthResponse>> auth(@RequestBody AuthRequest ar) {
|
||||
return userRepository.findByUsername(ar.getUsername()).map((userDetails) -> {
|
||||
if (passwordEncoder.encode(ar.getPassword()).equals(userDetails.getPassword())) {
|
||||
return ResponseEntity.ok(new AuthResponse(jwtTokenUtil.generateToken(userDetails)));
|
||||
return ResponseEntity.ok(new AuthResponse(jwtUtil.generateToken(userDetails)));
|
||||
} else {
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
* Ardiansyah | http://ard.web.id
|
||||
*
|
||||
*/
|
||||
package id.web.ard.springbootwebfluxjjwt.rest;
|
||||
package com.ard333.springbootwebfluxjjwt.rest;
|
||||
|
||||
import id.web.ard.springbootwebfluxjjwt.model.Message;
|
||||
import com.ard333.springbootwebfluxjjwt.model.Message;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -1,10 +1,6 @@
|
||||
/*
|
||||
* Ardiansyah | http://ard.web.id
|
||||
*
|
||||
*/
|
||||
package id.web.ard.springbootwebfluxjjwt.security;
|
||||
package com.ard333.springbootwebfluxjjwt.security;
|
||||
|
||||
import id.web.ard.springbootwebfluxjjwt.security.model.Role;
|
||||
import com.ard333.springbootwebfluxjjwt.security.model.Role;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
||||
@@ -16,11 +12,10 @@ import reactor.core.publisher.Mono;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.security.web.server.context.ServerSecurityContextRepository;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ardiansyah
|
||||
* @author ard333
|
||||
*/
|
||||
@Component
|
||||
public class AuthenticationManager implements ReactiveAuthenticationManager {
|
||||
@@ -32,29 +27,25 @@ public class AuthenticationManager implements ReactiveAuthenticationManager {
|
||||
public Mono<Authentication> authenticate(Authentication authentication) {
|
||||
String authToken = authentication.getCredentials().toString();
|
||||
|
||||
String username = null;
|
||||
String username;
|
||||
try {
|
||||
username = jwtUtil.getUsernameFromToken(authToken);
|
||||
} catch (Exception e) {
|
||||
username = null;
|
||||
}
|
||||
if (username != null) {
|
||||
if (username != null && jwtUtil.validateToken(authToken)) {
|
||||
Claims claims = jwtUtil.getAllClaimsFromToken(authToken);
|
||||
if (jwtUtil.validateToken(authToken)) {
|
||||
List<String> rolesMap = claims.get("role", List.class);
|
||||
List<Role> roles = new ArrayList<>();
|
||||
for (String rolemap : rolesMap) {
|
||||
roles.add(Role.valueOf(rolemap));
|
||||
}
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
|
||||
username,
|
||||
null,
|
||||
roles.stream().map(authority -> new SimpleGrantedAuthority(authority.name())).collect(Collectors.toList())
|
||||
);
|
||||
return Mono.just(auth);
|
||||
} else {
|
||||
return Mono.empty();
|
||||
List<String> rolesMap = claims.get("role", List.class);
|
||||
List<Role> roles = new ArrayList<>();
|
||||
for (String rolemap : rolesMap) {
|
||||
roles.add(Role.valueOf(rolemap));
|
||||
}
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
|
||||
username,
|
||||
null,
|
||||
roles.stream().map(authority -> new SimpleGrantedAuthority(authority.name())).collect(Collectors.toList())
|
||||
);
|
||||
return Mono.just(auth);
|
||||
} else {
|
||||
return Mono.empty();
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
/*
|
||||
* Ardiansyah | http://ard.web.id
|
||||
*
|
||||
*/
|
||||
package id.web.ard.springbootwebfluxjjwt.security;
|
||||
package com.ard333.springbootwebfluxjjwt.security;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.reactive.config.CorsRegistry;
|
||||
@@ -11,7 +7,7 @@ import org.springframework.web.reactive.config.WebFluxConfigurer;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ardiansyah
|
||||
* @author ard333
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebFlux
|
||||
@@ -1,10 +1,6 @@
|
||||
/*
|
||||
* Ardiansyah | http://ard.web.id
|
||||
*
|
||||
*/
|
||||
package id.web.ard.springbootwebfluxjjwt.security;
|
||||
package com.ard333.springbootwebfluxjjwt.security;
|
||||
|
||||
import id.web.ard.springbootwebfluxjjwt.model.User;
|
||||
import com.ard333.springbootwebfluxjjwt.model.User;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
@@ -17,7 +13,7 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ardiansyah
|
||||
* @author ard333
|
||||
*/
|
||||
@Component
|
||||
public class JWTUtil implements Serializable {
|
||||
@@ -1,8 +1,4 @@
|
||||
/*
|
||||
* Ardiansyah | http://ard.web.id
|
||||
*
|
||||
*/
|
||||
package id.web.ard.springbootwebfluxjjwt.security;
|
||||
package com.ard333.springbootwebfluxjjwt.security;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
@@ -15,7 +11,7 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ardiansyah
|
||||
* @author ard333
|
||||
*/
|
||||
@Component
|
||||
public class PBKDF2Encoder implements PasswordEncoder{
|
||||
@@ -1,8 +1,4 @@
|
||||
/*
|
||||
* Ardiansyah | http://ard.web.id
|
||||
*
|
||||
*/
|
||||
package id.web.ard.springbootwebfluxjjwt.security;
|
||||
package com.ard333.springbootwebfluxjjwt.security;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
@@ -18,7 +14,7 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ardiansyah
|
||||
* @author ard333
|
||||
*/
|
||||
@Component
|
||||
public class SecurityContextRepository implements ServerSecurityContextRepository{
|
||||
@@ -1,4 +1,4 @@
|
||||
package id.web.ard.springbootwebfluxjjwt.security;
|
||||
package com.ard333.springbootwebfluxjjwt.security;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -10,7 +10,7 @@ import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ardiansyah
|
||||
* @author ard333
|
||||
*/
|
||||
@EnableWebFluxSecurity
|
||||
@EnableReactiveMethodSecurity
|
||||
@@ -1,8 +1,4 @@
|
||||
/*
|
||||
* Ardiansyah | http://ard.web.id
|
||||
*
|
||||
*/
|
||||
package id.web.ard.springbootwebfluxjjwt.security.model;
|
||||
package com.ard333.springbootwebfluxjjwt.security.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
@@ -11,7 +7,7 @@ import lombok.ToString;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ardiansyah
|
||||
* @author ard333
|
||||
*/
|
||||
@Data @NoArgsConstructor @AllArgsConstructor @ToString
|
||||
public class AuthRequest {
|
||||
@@ -1,8 +1,4 @@
|
||||
/*
|
||||
* Ardiansyah | http://ard.web.id
|
||||
*
|
||||
*/
|
||||
package id.web.ard.springbootwebfluxjjwt.security.model;
|
||||
package com.ard333.springbootwebfluxjjwt.security.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
@@ -11,7 +7,7 @@ import lombok.ToString;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ardiansyah
|
||||
* @author ard333
|
||||
*/
|
||||
@Data @NoArgsConstructor @AllArgsConstructor @ToString
|
||||
public class AuthResponse {
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.ard333.springbootwebfluxjjwt.security.model;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ard333
|
||||
*/
|
||||
public enum Role {
|
||||
ROLE_USER, ROLE_ADMIN
|
||||
}
|
||||
@@ -1,11 +1,7 @@
|
||||
/*
|
||||
* Ardiansyah | http://ard.web.id
|
||||
*
|
||||
*/
|
||||
package id.web.ard.springbootwebfluxjjwt.service;
|
||||
package com.ard333.springbootwebfluxjjwt.service;
|
||||
|
||||
import id.web.ard.springbootwebfluxjjwt.model.User;
|
||||
import id.web.ard.springbootwebfluxjjwt.security.model.Role;
|
||||
import com.ard333.springbootwebfluxjjwt.model.User;
|
||||
import com.ard333.springbootwebfluxjjwt.security.model.Role;
|
||||
import java.util.Arrays;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -13,7 +9,7 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ardiansyah
|
||||
* @author ard333
|
||||
*/
|
||||
@Service
|
||||
public class UserService {
|
||||
@@ -49,6 +45,4 @@ public class UserService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Ardiansyah | http://ard.web.id
|
||||
*
|
||||
*/
|
||||
package id.web.ard.springbootwebfluxjjwt.security;
|
||||
|
||||
import id.web.ard.springbootwebfluxjjwt.service.UserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ardiansyah
|
||||
*/
|
||||
@Service
|
||||
public class UserDetailsServiceImpl implements ReactiveUserDetailsService {
|
||||
|
||||
@Autowired
|
||||
private UserService userRepository;
|
||||
|
||||
@Override
|
||||
public Mono<UserDetails> findByUsername(String username) {
|
||||
return userRepository.findUserDetailsByUsername(username);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
/*
|
||||
* Ardiansyah | http://ard.web.id
|
||||
*
|
||||
*/
|
||||
package id.web.ard.springbootwebfluxjjwt.security.model;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author ardiansyah
|
||||
*/
|
||||
public enum Role {
|
||||
ROLE_USER, ROLE_ADMIN
|
||||
}
|
||||
Reference in New Issue
Block a user