Spring Boot 2
JwtAuthenticationFilter
package com.fresco.ecommerce.config;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import com.fresco.ecommerce.models.User;
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
JwtUtil jwtUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String jwtToken = request.getHeader("JWT");
if (jwtToken == null) {
filterChain.doFilter(request, response);
return;
}
User user = jwtUtil.getUser(jwtToken);
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (user != null && authentication == null) {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUsername(), null, user.getAuthorities());
jwtUtil.validateToken(jwtToken);
SecurityContextHolder.getContext().setAuthentication(token);
}
filterChain.doFilter(request, response);
}
}
ApiSecurityConfig
package com.fresco.ecommerce.config;
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.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.fresco.ecommerce.service.UserAuthService;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ApiSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
JwtAuthenticationFilter jwtAuthenticationFilter;
@Autowired
UserAuthService userAuthService;
@Override
public void configure(WebSecurity web) throws Exception {
}
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userAuthService).passwordEncoder(NoOpPasswordEncoder.getInstance());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable)
.cors(AbstractHttpConfigurer::disable)
.authorizeRequests(requests -> requests
.antMatchers("/**").permitAll()
.anyRequest().authenticated())
.sessionManagement(sessionConfigurer -> sessionConfigurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.formLogin(AbstractHttpConfigurer::disable);
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
ApiAuthenticationEntryPoint
package com.fresco.ecommerce.config;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
@Component
public class ApiAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
JwtUtil
package com.fresco.ecommerce.config;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.fresco.ecommerce.models.User;
import com.fresco.ecommerce.service.UserAuthService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
@Component
public class JwtUtil {
@Value("${jwt.secret}")
private String SECRET_KEY;
@Value("${jwt.token.validity}")
private long validity;
@Autowired
UserAuthService userAuthService;
public User getUser(final String token) {
String userName = extractSubject(token);
return userAuthService.loadUserByUsername(userName);
}
private String extractSubject(String token) {
Claims claim = extractClaims(token);
return claim.getSubject();
}
private Claims extractClaims(String token) {
return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
}
public String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(validity + System.currentTimeMillis()))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
public void validateToken(final String token) {
Date expirationTime = extractExpiration(token);
if (expirationTime.before(new Date())) {
throw new ExpiredJwtException(null, null, "Token Expired");
}
}
private Date extractExpiration(String token) {
return extractClaims(token).getExpiration();
}
}
PublicController
package com.fresco.ecommerce.controllers;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.fresco.ecommerce.config.JwtUtil;
import com.fresco.ecommerce.models.Product;
import com.fresco.ecommerce.models.User;
import com.fresco.ecommerce.repo.ProductRepo;
@RestController
@RequestMapping("/api/public")
public class PublicController {
@Autowired
AuthenticationManager authenticationManager;
@Autowired
JwtUtil jwtUtil;
@Autowired
ProductRepo productRepo;
@GetMapping("/product/search")
public List<Product> getProducts(@RequestParam("keyword") String key) {
return productRepo.findByProductNameContainingIgnoreCaseOrCategoryCategoryNameContainingIgnoreCase(key, key);
}
@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody User user) {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword()));
String jwtToken = jwtUtil.generateToken(user.getUsername());
return ResponseEntity.ok(jwtToken);
}
}
User Entity
package com.fresco.ecommerce.models;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
@Entity
public class User implements UserDetails {
private static final long serialVersionUID = 5536306799835655715L;
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
private Integer userId;
@Column(unique = true)
private String username;
private String password;
@ElementCollection(targetClass = Role.class, fetch = FetchType.EAGER)
@CollectionTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"))
@Enumerated(EnumType.STRING)
private Set<Role> roles;
public User() {
super();
}
public User(String username, String password, Set<Role> roles) {
super();
this.username = username;
this.password = password;
this.roles = roles;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
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 Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
@Override
public String toString() {
return "User [userId=" + userId + ", username=" + username + ", password=" + password + ", roles=" + roles + "]";
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.roles.stream().map(r -> new RoleGrantedAuthority(r.name())).collect(Collectors.toList());
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
Role
package com.fresco.ecommerce.models;
import org.springframework.security.core.GrantedAuthority;
public enum Role {
CONSUMER, SELLER;
}
class
RoleGrantedAuthority implements GrantedAuthority {
private static final long serialVersionUID = -3408298481881657796L;
String role;
@Override
public String getAuthority() {
return role;
}
public RoleGrantedAuthority(String role) {
this.role = role;
}
}