App
Web Spring application with token auth, jjwt dependency.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
</dependency>
<dependencies>
package com.minte9.jwt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
Controller
REST controller that implements the auth with username/password.
package com.minte9.jwt;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
@RestController
public class AppRestController {
@ Autowired
private Environment env;
@RequestMapping("/hello")
public String hello() {
return "Hello World! \n";
}
@PostMapping("/token")
public User genToken(
@RequestParam("user") String username,
@RequestParam("password") String pwd) {
User user = new User();
user.setUser(username);
String envUser = env.getProperty("spring.security.user.name");
String envPass = env.getProperty("spring.security.user.password");
if(username.equals(envUser) && pwd.equals(envPass)) {
String token = getJWTToken(username);
user.setToken(token);
}
return user;
}
private String getJWTToken(String username) {
String secretKey = "myTokenSecretKey";
List<GrantedAuthority> grantedAuthorities = AuthorityUtils
.commaSeparatedStringToAuthorityList("ROLE_USER");
String token = Jwts
.builder()
.setId("minte9JWT")
.setSubject(username)
.claim("authorities", grantedAuthorities.stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList()))
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 600000))
.signWith(SignatureAlgorithm.HS512, secretKey.getBytes())
.compact();
return "Bearer " + token;
}
}
Config
Calls to /user are allowed, but all other calls require authentication.
package com.minte9.jwt;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.*;
import org.springframework.security.web.authentication.*;
@EnableWebSecurity
@Configuration
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.addFilterAfter(
new JWTAuthorizationFilter(),
UsernamePasswordAuthenticationFilter.class // Look Here
)
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/token").permitAll()
.anyRequest().authenticated();
}
}
Authorization
Implement the autorization process with JWTAuthorizationFilter class.
package com.minte9.jwt;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.*;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;
public class JWTAuthorizationFilter extends OncePerRequestFilter {
private final String HEADER = "Authorization";
private final String PREFIX = "Bearer ";
private final String SECRET = "myTokenSecretKey";
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain chain)
throws ServletException, IOException {
try {
if (checkJWTToken(request, response)) {
Claims claims = validateToken(request);
if (claims.get("authorities") != null) {
setUpSpringAuthentication(claims);
} else {
SecurityContextHolder.clearContext();
}
}else {
SecurityContextHolder.clearContext();
}
chain.doFilter(request, response);
} catch (ExpiredJwtException |
UnsupportedJwtException | MalformedJwtException e) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response = (HttpServletResponse) response;
response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
return;
}
}
private Claims validateToken(HttpServletRequest request) {
String jwtToken = request.getHeader(HEADER).replace(PREFIX, );
JwtParser jwtParser = Jwts.parser();
jwtParser.setSigningKey(SECRET.getBytes());
return jwtParser.parseClaimsJws(jwtToken).getBody();
}
private void setUpSpringAuthentication(Claims claims) {
@SuppressWarnings("unchecked")
List<String> authorities = (List<String>) claims.get("authorities");
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(
claims.getSubject(), null, authorities.stream()
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList()
)
);
SecurityContextHolder.getContext().setAuthentication(auth);
}
private boolean checkJWTToken(
HttpServletRequest request,
HttpServletResponse res) {
String authenticationHeader = request.getHeader(HEADER);
if ( authenticationHeader == null ||
!authenticationHeader.startsWith(PREFIX))
return false;
return true;
}
}
Token
The client uses token to access the protected resources.
curl http://localhost:8080/hello
URL='http://localhost:8080/token?user=myuser&password=mypass'
RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" $URL)
TOKEN=$(echo $RESPONSE | jq -r '.token')
echo $TOKEN
curl -H "Authorization: Bearer $TOKEN" http://localhost:8080/hello