├── README.md
├── Spring Security ile JWT Entegrasyonu.pdf
├── pom.xml
└── src
└── main
├── java
└── com
│ └── demo
│ └── app
│ ├── Application.java
│ ├── controller
│ ├── AuthenticationController.java
│ └── UserController.java
│ ├── model
│ ├── AuthenticationResponse.java
│ └── UserContext.java
│ ├── security
│ ├── annotation
│ │ └── IdGuard.java
│ ├── aspect
│ │ └── IdGuardAspect.java
│ ├── config
│ │ └── ApiSecurityConfig.java
│ ├── entrypoint
│ │ └── fail
│ │ │ └── AuthenticationFailureEntryPoint.java
│ ├── jwt
│ │ ├── filter
│ │ │ └── JwtAuthorizationFilter.java
│ │ └── manager
│ │ │ ├── EncryptionManager.java
│ │ │ └── JwtTokenManager.java
│ ├── provider
│ │ └── UserAuthenticationProvider.java
│ └── service
│ │ └── userdetails
│ │ └── AuthenticationUserDetailsService.java
│ ├── service
│ ├── AuthenticationService.java
│ └── UserService.java
│ └── swagger
│ └── Swagger2Configuration.java
└── resources
└── application.properties
/README.md:
--------------------------------------------------------------------------------
1 | # spring-security-jwt-integration
2 | JWT Integration Demo App with Spring Security
3 |
4 | Etkinlik linki :)
5 |
6 | https://www.youtube.com/watch?v=7ej-cWEGKwc
7 |
--------------------------------------------------------------------------------
/Spring Security ile JWT Entegrasyonu.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/batux/spring-security-jwt-integration/e5d4943d0cf2af855aee83a7c9fe6d78ceea3dd7/Spring Security ile JWT Entegrasyonu.pdf
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.example
8 | spring-security-jwt-demo
9 | 1.0-SNAPSHOT
10 |
11 |
12 | org.springframework.boot
13 | spring-boot-starter-parent
14 | 2.4.0
15 |
16 |
17 |
18 | 11
19 | 11
20 |
21 |
22 |
23 |
24 | org.springframework.boot
25 | spring-boot-starter
26 |
27 |
28 | org.springframework.boot
29 | spring-boot-starter-web
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-starter-aop
34 |
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-security
39 |
40 |
41 | io.jsonwebtoken
42 | jjwt
43 | 0.9.1
44 |
45 |
46 | commons-codec
47 | commons-codec
48 | 1.11
49 |
50 |
51 |
52 | io.springfox
53 | springfox-swagger2
54 | 2.9.2
55 |
56 |
57 | io.springfox
58 | springfox-swagger-ui
59 | 2.9.2
60 |
61 |
62 | org.projectlombok
63 | lombok
64 |
65 |
66 | javax.xml.bind
67 | jaxb-api
68 | 2.3.1
69 |
70 |
71 |
72 |
73 | spring-security-jwt-demo
74 |
75 |
76 |
77 | org.springframework.boot
78 | spring-boot-maven-plugin
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/src/main/java/com/demo/app/Application.java:
--------------------------------------------------------------------------------
1 | package com.demo.app;
2 |
3 | import com.demo.app.security.config.ApiSecurityConfig;
4 | import com.demo.app.swagger.Swagger2Configuration;
5 | import org.springframework.boot.SpringApplication;
6 | import org.springframework.boot.autoconfigure.SpringBootApplication;
7 | import org.springframework.context.annotation.Import;
8 | import springfox.documentation.swagger2.annotations.EnableSwagger2;
9 |
10 | @EnableSwagger2
11 | @SpringBootApplication
12 | @Import( { ApiSecurityConfig.class, Swagger2Configuration.class } )
13 | public class Application {
14 |
15 | public static void main(String[] args) {
16 | SpringApplication.run(Application.class, args);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/demo/app/controller/AuthenticationController.java:
--------------------------------------------------------------------------------
1 | package com.demo.app.controller;
2 |
3 | import com.demo.app.model.AuthenticationResponse;
4 | import com.demo.app.service.AuthenticationService;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.http.HttpHeaders;
7 | import org.springframework.http.HttpStatus;
8 | import org.springframework.http.ResponseEntity;
9 | import org.springframework.security.authentication.BadCredentialsException;
10 | import org.springframework.web.bind.annotation.RequestHeader;
11 | import org.springframework.web.bind.annotation.RequestMapping;
12 | import org.springframework.web.bind.annotation.RequestMethod;
13 | import org.springframework.web.bind.annotation.RestController;
14 |
15 | @RestController
16 | @RequestMapping(path = "/rest/api/v1")
17 | public class AuthenticationController {
18 |
19 | @Autowired
20 | private AuthenticationService authenticationService;
21 |
22 |
23 | @RequestMapping(path = "/login", method = RequestMethod.POST)
24 | public ResponseEntity login(@RequestHeader(HttpHeaders.AUTHORIZATION) String authorization) {
25 | try {
26 |
27 | AuthenticationResponse response = authenticationService.authenticate(authorization);
28 | return ResponseEntity.ok()
29 | .header(HttpHeaders.AUTHORIZATION, response.getToken())
30 | .body(response);
31 |
32 | } catch (BadCredentialsException ex) {
33 | return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/demo/app/controller/UserController.java:
--------------------------------------------------------------------------------
1 | package com.demo.app.controller;
2 |
3 | import com.demo.app.model.UserContext;
4 | import com.demo.app.security.annotation.IdGuard;
5 | import com.demo.app.service.UserService;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.http.ResponseEntity;
8 | import org.springframework.web.bind.annotation.*;
9 |
10 | @RestController
11 | @RequestMapping(path = "/rest/api/v1/user")
12 | public class UserController {
13 |
14 | @Autowired
15 | private UserService userService;
16 |
17 |
18 | @RequestMapping(method = RequestMethod.POST)
19 | public ResponseEntity register(@RequestBody UserContext userContext) {
20 |
21 | return ResponseEntity.ok().body(userService.save(userContext));
22 | }
23 |
24 | @IdGuard(parameterIndex = 0)
25 | @RequestMapping(path = "/{userId}", method = RequestMethod.GET)
26 | public ResponseEntity load(@PathVariable("userId") Integer userId) {
27 |
28 | return ResponseEntity.ok().body(userService.load(userId));
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/demo/app/model/AuthenticationResponse.java:
--------------------------------------------------------------------------------
1 | package com.demo.app.model;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | import java.io.Serializable;
8 |
9 | @Data
10 | @NoArgsConstructor
11 | @AllArgsConstructor
12 | public class AuthenticationResponse implements Serializable {
13 |
14 | private static final long serialVersionUID = 8929499253726531083L;
15 |
16 | private Integer userId;
17 | private String token;
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/demo/app/model/UserContext.java:
--------------------------------------------------------------------------------
1 | package com.demo.app.model;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | import java.io.Serializable;
8 |
9 | @Data
10 | @NoArgsConstructor
11 | @AllArgsConstructor
12 | public class UserContext implements Serializable {
13 |
14 | private static final long serialVersionUID = -8099349063069095844L;
15 |
16 | private Integer id;
17 | private String name;
18 | private String surname;
19 | private String email;
20 | private String password;
21 | private String type;
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/src/main/java/com/demo/app/security/annotation/IdGuard.java:
--------------------------------------------------------------------------------
1 | package com.demo.app.security.annotation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | @Retention(RetentionPolicy.RUNTIME)
9 | @Target(ElementType.METHOD)
10 | public @interface IdGuard {
11 |
12 | int parameterIndex();
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/demo/app/security/aspect/IdGuardAspect.java:
--------------------------------------------------------------------------------
1 | package com.demo.app.security.aspect;
2 |
3 | import javax.servlet.http.HttpServletRequest;
4 |
5 | import com.demo.app.security.annotation.IdGuard;
6 | import com.demo.app.security.jwt.manager.EncryptionManager;
7 | import com.demo.app.security.jwt.manager.JwtTokenManager;
8 | import org.aspectj.lang.JoinPoint;
9 | import org.aspectj.lang.annotation.Aspect;
10 | import org.aspectj.lang.annotation.Before;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.stereotype.Component;
13 | import org.springframework.util.StringUtils;
14 | import org.springframework.web.context.request.RequestContextHolder;
15 | import org.springframework.web.context.request.ServletRequestAttributes;
16 |
17 | @Aspect
18 | @Component
19 | public class IdGuardAspect {
20 |
21 | @Autowired
22 | private JwtTokenManager tokenManager;
23 |
24 | @Autowired
25 | private EncryptionManager encryptionManager;
26 |
27 |
28 | @Before("@annotation(idGuard)")
29 | public void execute(JoinPoint joinPoint, IdGuard idGuard) {
30 |
31 | int argIndex = idGuard.parameterIndex();
32 | if(argIndex < 0){
33 | argIndex = 0;
34 | }
35 |
36 | Object[] args = joinPoint.getArgs();
37 | if(args == null || args.length == 0) {
38 | throw new RuntimeException("ACCESS ERROR FOR INVALID RESOURCE");
39 | }
40 |
41 | Object idParameterObj = args[argIndex];
42 | if(idParameterObj == null) {
43 | throw new RuntimeException("ACCESS ERROR FOR INVALID RESOURCE");
44 | }
45 |
46 | String expectedTicket = encryptionManager.encrypt(idParameterObj.toString());
47 |
48 | HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
49 | String token = tokenManager.extractJwtFromRequest(request);
50 | if(!StringUtils.hasText(token)) {
51 | throw new RuntimeException("ACCESS ERROR FOR INVALID RESOURCE");
52 | }
53 |
54 | String realTicket = tokenManager.extractTicket(token);
55 | if(!(StringUtils.hasText(expectedTicket) && expectedTicket.contains(realTicket)) ) {
56 | throw new RuntimeException("ACCESS ERROR FOR INVALID RESOURCE");
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/com/demo/app/security/config/ApiSecurityConfig.java:
--------------------------------------------------------------------------------
1 | package com.demo.app.security.config;
2 |
3 | import com.demo.app.security.entrypoint.fail.AuthenticationFailureEntryPoint;
4 | import com.demo.app.security.jwt.filter.JwtAuthorizationFilter;
5 | import com.demo.app.security.jwt.manager.JwtTokenManager;
6 | import com.demo.app.security.provider.UserAuthenticationProvider;
7 | import com.demo.app.security.service.userdetails.AuthenticationUserDetailsService;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.context.annotation.Bean;
10 | import org.springframework.context.annotation.Configuration;
11 | import org.springframework.core.annotation.Order;
12 | import org.springframework.http.HttpMethod;
13 | import org.springframework.security.authentication.AuthenticationManager;
14 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
15 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
16 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
17 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
18 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
19 | import org.springframework.security.config.http.SessionCreationPolicy;
20 | import org.springframework.security.crypto.password.NoOpPasswordEncoder;
21 | import org.springframework.web.cors.CorsConfiguration;
22 | import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
23 | import org.springframework.web.filter.CorsFilter;
24 |
25 | @Configuration
26 | @EnableWebSecurity
27 | @Order(1)
28 | public class ApiSecurityConfig extends WebSecurityConfigurerAdapter {
29 |
30 | @Autowired
31 | private AuthenticationFailureEntryPoint failureEntryPoint;
32 |
33 | @Autowired
34 | private JwtTokenManager tokenManager;
35 |
36 | @Autowired
37 | private AuthenticationUserDetailsService authenticationUserDetailsService;
38 |
39 |
40 | @Override
41 | public void configure(HttpSecurity http) throws Exception {
42 |
43 | http = http.cors().and().csrf().disable();
44 |
45 | http = http
46 | .sessionManagement()
47 | .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
48 | .and();
49 |
50 | http = http
51 | .exceptionHandling()
52 | .authenticationEntryPoint(failureEntryPoint)
53 | .and();
54 |
55 | http.authorizeRequests()
56 | .antMatchers("/v2/api-docs", "/api-docs",
57 | "/configuration/ui", "/configuration/security",
58 | "/swagger-ui/**", "/swagger-resources/**", "/swagger-ui.html", "/webjars/**").permitAll()
59 | .antMatchers(HttpMethod.POST, "/rest/api/v1/login").permitAll()
60 | .antMatchers(HttpMethod.POST, "/rest/api/v1/user").permitAll()
61 | .anyRequest().authenticated()
62 | .and()
63 | .addFilter(new JwtAuthorizationFilter(authenticationManager(), tokenManager));
64 | }
65 |
66 | @Override
67 | protected void configure(AuthenticationManagerBuilder auth) {
68 |
69 | UserAuthenticationProvider authenticationProvider = new UserAuthenticationProvider();
70 | authenticationProvider.setPasswordEncoder(NoOpPasswordEncoder.getInstance());
71 | authenticationProvider.setUserDetailsService(authenticationUserDetailsService);
72 | auth.authenticationProvider(authenticationProvider);
73 | }
74 |
75 | @Bean
76 | @Override
77 | public AuthenticationManager authenticationManagerBean() throws Exception {
78 | return super.authenticationManagerBean();
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/com/demo/app/security/entrypoint/fail/AuthenticationFailureEntryPoint.java:
--------------------------------------------------------------------------------
1 | package com.demo.app.security.entrypoint.fail;
2 |
3 | import java.io.IOException;
4 |
5 | import javax.servlet.ServletException;
6 | import javax.servlet.http.HttpServletRequest;
7 | import javax.servlet.http.HttpServletResponse;
8 |
9 | import org.springframework.security.core.AuthenticationException;
10 | import org.springframework.security.web.AuthenticationEntryPoint;
11 | import org.springframework.stereotype.Component;
12 |
13 | @Component
14 | public class AuthenticationFailureEntryPoint implements AuthenticationEntryPoint {
15 |
16 | @Override
17 | public void commence(HttpServletRequest request, HttpServletResponse response,
18 | AuthenticationException authException) throws IOException, ServletException {
19 |
20 | response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
21 | response.addHeader("INVALID-AUTH", "Invalid authentication attempt!");
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/demo/app/security/jwt/filter/JwtAuthorizationFilter.java:
--------------------------------------------------------------------------------
1 | package com.demo.app.security.jwt.filter;
2 |
3 | import javax.servlet.FilterChain;
4 | import javax.servlet.http.HttpServletRequest;
5 | import javax.servlet.http.HttpServletResponse;
6 |
7 | import com.demo.app.security.jwt.manager.JwtTokenManager;
8 | import org.springframework.http.HttpHeaders;
9 | import org.springframework.security.authentication.AuthenticationManager;
10 | import org.springframework.security.authentication.BadCredentialsException;
11 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
12 | import org.springframework.security.core.authority.SimpleGrantedAuthority;
13 | import org.springframework.security.core.context.SecurityContextHolder;
14 | import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
15 | import org.springframework.util.StringUtils;
16 |
17 | import io.jsonwebtoken.ExpiredJwtException;
18 |
19 | import java.util.List;
20 |
21 | public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
22 |
23 | private JwtTokenManager tokenManager;
24 |
25 | public JwtAuthorizationFilter(AuthenticationManager authenticationManager, JwtTokenManager tokenManager) {
26 | super(authenticationManager);
27 | this.tokenManager = tokenManager;
28 | }
29 |
30 | @Override
31 | protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
32 |
33 | try {
34 |
35 | String jwtToken = tokenManager.extractJwtFromRequest(request);
36 | if(jwtToken == null) {
37 | chain.doFilter(request, response);
38 | return;
39 | }
40 |
41 | if(StringUtils.hasText(jwtToken) && tokenManager.validate(jwtToken)) {
42 |
43 | String principal = tokenManager.getUsernameFromToken(jwtToken);
44 | List roles = tokenManager.getRolesFromToken(jwtToken);
45 |
46 | UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
47 | principal, null, roles);
48 |
49 | SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
50 | chain.doFilter(request, response);
51 | return;
52 | }
53 | else {
54 | if(isBasicAuthRequest(request)) {
55 | SecurityContextHolder.clearContext();
56 | chain.doFilter(request, response);
57 | return;
58 | }
59 | prepareInvalidAuthResponse(response);
60 | return;
61 | }
62 | }
63 | catch (ExpiredJwtException | BadCredentialsException ex) {
64 | prepareInvalidAuthResponse(response);
65 | return;
66 | }
67 | catch(Exception ex) {
68 | prepareInvalidAuthResponse(response);
69 | return;
70 | }
71 | }
72 |
73 | private boolean isBasicAuthRequest(HttpServletRequest request) {
74 | String data = request.getHeader(HttpHeaders.AUTHORIZATION);
75 | return (StringUtils.hasText(data) && data.startsWith("Basic "));
76 | }
77 |
78 | private void prepareInvalidAuthResponse(HttpServletResponse response) {
79 | SecurityContextHolder.clearContext();
80 | response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
81 | response.addHeader("INVALID-AUTH", "Invalid authentication attempt!");
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/com/demo/app/security/jwt/manager/EncryptionManager.java:
--------------------------------------------------------------------------------
1 | package com.demo.app.security.jwt.manager;
2 |
3 | import org.apache.commons.codec.digest.DigestUtils;
4 | import org.springframework.stereotype.Component;
5 | import org.springframework.util.StringUtils;
6 |
7 | @Component
8 | public class EncryptionManager {
9 |
10 | private final String salt = "DEVTECH-SECRET*!>>";
11 |
12 | public String encrypt(String payload) {
13 |
14 | if(!StringUtils.hasText(payload)) {
15 | return "";
16 | }
17 | return DigestUtils.sha256Hex(payload + salt);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/demo/app/security/jwt/manager/JwtTokenManager.java:
--------------------------------------------------------------------------------
1 | package com.demo.app.security.jwt.manager;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collection;
5 | import java.util.Date;
6 | import java.util.HashMap;
7 | import java.util.List;
8 | import java.util.Map;
9 |
10 | import javax.servlet.http.HttpServletRequest;
11 |
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.beans.factory.annotation.Value;
14 | import org.springframework.http.HttpHeaders;
15 | import org.springframework.security.authentication.BadCredentialsException;
16 | import org.springframework.security.core.GrantedAuthority;
17 | import org.springframework.security.core.authority.SimpleGrantedAuthority;
18 | import org.springframework.security.core.userdetails.UserDetails;
19 | import org.springframework.stereotype.Component;
20 | import org.springframework.util.StringUtils;
21 |
22 | import io.jsonwebtoken.Claims;
23 | import io.jsonwebtoken.ExpiredJwtException;
24 | import io.jsonwebtoken.Jwts;
25 | import io.jsonwebtoken.MalformedJwtException;
26 | import io.jsonwebtoken.SignatureAlgorithm;
27 | import io.jsonwebtoken.SignatureException;
28 | import io.jsonwebtoken.UnsupportedJwtException;
29 | import lombok.extern.slf4j.Slf4j;
30 |
31 | @Slf4j
32 | @Component
33 | public class JwtTokenManager {
34 |
35 | @Value("${jwt.token.secret}")
36 | private String secret;
37 |
38 | @Value("${jwt.token.expiration.duration}")
39 | private long expirationDurationInMs;
40 |
41 | @Autowired
42 | private EncryptionManager encryptionManager;
43 |
44 |
45 | public String generateToken(UserDetails userDetails, Integer userId) {
46 |
47 | Map claims = new HashMap<>();
48 |
49 | Collection extends GrantedAuthority> roles = userDetails.getAuthorities();
50 |
51 | if (roles.contains(new SimpleGrantedAuthority("ADMIN"))) {
52 | claims.put("isAdmin", true);
53 | }
54 |
55 | if (roles.contains(new SimpleGrantedAuthority("USER"))) {
56 | claims.put("isUser", true);
57 | }
58 |
59 | if (userId != null && userId > 0) {
60 | claims.put("ticket", encryptionManager.encrypt(String.valueOf(userId)));
61 | }
62 |
63 | return doGenerateToken(claims, userDetails.getUsername());
64 | }
65 |
66 | public boolean validate(String authToken) {
67 |
68 | try {
69 | Jwts.parser().setSigningKey(secret).parseClaimsJws(authToken);
70 | return true;
71 | }
72 | catch (SignatureException | MalformedJwtException | UnsupportedJwtException | IllegalArgumentException ex) {
73 | throw new BadCredentialsException("INVALID_CREDENTIALS", ex);
74 | }
75 | catch (ExpiredJwtException ex) {
76 | throw ex;
77 | }
78 | }
79 |
80 | public String getUsernameFromToken(String token) {
81 |
82 | Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
83 | return claims.getSubject();
84 | }
85 |
86 | public List getRolesFromToken(String token) {
87 |
88 | Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
89 | List roles = new ArrayList(2);
90 |
91 | Boolean admin = claims.get("isAdmin", Boolean.class);
92 | if (admin != null && admin) {
93 | roles.add(new SimpleGrantedAuthority("ADMIN"));
94 | }
95 |
96 | Boolean user = claims.get("isUser", Boolean.class);
97 | if (user != null && user) {
98 | roles.add(new SimpleGrantedAuthority("USER"));
99 | }
100 | return roles;
101 | }
102 |
103 | public String extractTicket(String token) {
104 |
105 | Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
106 | return claims.get("ticket", String.class);
107 | }
108 |
109 | public String extractJwtFromRequest(HttpServletRequest request) {
110 | String data = request.getHeader(HttpHeaders.AUTHORIZATION);
111 | if (StringUtils.hasText(data) && data.startsWith("Bearer ")) {
112 | return data.substring(7, data.length());
113 | }
114 | return null;
115 | }
116 |
117 | private String doGenerateToken(Map claims, String subject) {
118 |
119 | long currentTimeMillis = System.currentTimeMillis();
120 | return Jwts.builder()
121 | .setClaims(claims)
122 | .setSubject(subject)
123 | .setIssuedAt(new Date(currentTimeMillis))
124 | .setExpiration(new Date(currentTimeMillis + expirationDurationInMs))
125 | .signWith(SignatureAlgorithm.HS512, secret)
126 | .compact();
127 |
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/src/main/java/com/demo/app/security/provider/UserAuthenticationProvider.java:
--------------------------------------------------------------------------------
1 | package com.demo.app.security.provider;
2 |
3 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
4 | import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
5 | import org.springframework.security.core.Authentication;
6 | import org.springframework.security.core.userdetails.UserDetails;
7 |
8 | public class UserAuthenticationProvider extends DaoAuthenticationProvider {
9 |
10 | @Override
11 | protected Authentication createSuccessAuthentication(Object principal, Authentication authentication, UserDetails user) {
12 |
13 | return new UsernamePasswordAuthenticationToken(principal, user.getPassword(), user.getAuthorities());
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/demo/app/security/service/userdetails/AuthenticationUserDetailsService.java:
--------------------------------------------------------------------------------
1 | package com.demo.app.security.service.userdetails;
2 |
3 | import com.demo.app.model.UserContext;
4 | import com.demo.app.service.UserService;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.security.core.userdetails.User;
7 | import org.springframework.security.core.userdetails.UserDetails;
8 | import org.springframework.security.core.userdetails.UserDetailsService;
9 | import org.springframework.security.core.userdetails.UsernameNotFoundException;
10 | import org.springframework.stereotype.Component;
11 |
12 | @Component
13 | public class AuthenticationUserDetailsService implements UserDetailsService {
14 |
15 | @Autowired
16 | private UserService userService;
17 |
18 | @Override
19 | public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
20 |
21 | UserContext userContext = userService.load(email);
22 | if(userContext == null) {
23 | throw new UsernameNotFoundException("User not found!");
24 | }
25 | return User.withUsername(userContext.getEmail())
26 | .password(userContext.getPassword())
27 | .authorities("USER")
28 | .build();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/demo/app/service/AuthenticationService.java:
--------------------------------------------------------------------------------
1 | package com.demo.app.service;
2 |
3 | import com.demo.app.model.AuthenticationResponse;
4 | import com.demo.app.model.UserContext;
5 | import com.demo.app.security.jwt.manager.JwtTokenManager;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.security.authentication.AuthenticationManager;
8 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
9 | import org.springframework.security.core.Authentication;
10 | import org.springframework.security.core.userdetails.User;
11 |
12 | import org.springframework.stereotype.Service;
13 | import org.springframework.util.StringUtils;
14 |
15 | import java.nio.charset.StandardCharsets;
16 | import java.util.Base64;
17 |
18 |
19 | @Service
20 | public class AuthenticationService {
21 |
22 | @Autowired
23 | private UserService userService;
24 |
25 | @Autowired
26 | private AuthenticationManager authenticationManager;
27 |
28 | @Autowired
29 | private JwtTokenManager tokenManager;
30 |
31 |
32 | public AuthenticationResponse authenticate(String authorization) {
33 |
34 | if(!StringUtils.hasText(authorization)) {
35 | throw new RuntimeException("INVALID AUTH PAYLOAD");
36 | }
37 |
38 | String[] httpBasicAuthPayload = parseHttpBasicPayload(authorization);
39 | String email = httpBasicAuthPayload[0];
40 | String password = httpBasicAuthPayload[1];
41 |
42 | Authentication authenticate = authenticationManager
43 | .authenticate(
44 | new UsernamePasswordAuthenticationToken(email, password)
45 | );
46 |
47 | User user = (User) authenticate.getPrincipal();
48 | if(user == null) {
49 | throw new RuntimeException("USER NOT FOUND");
50 | }
51 |
52 | UserContext userContext = userService.load(email);
53 | String jwtToken = tokenManager.generateToken(user, userContext.getId());
54 | return new AuthenticationResponse(userContext.getId(), jwtToken);
55 | }
56 |
57 | private String[] parseHttpBasicPayload(String authorization) {
58 |
59 | if (authorization != null && authorization.toLowerCase().startsWith("basic")) {
60 |
61 | String base64Credentials = authorization.substring("Basic".length()).trim();
62 | byte[] credDecoded = Base64.getDecoder().decode(base64Credentials);
63 | String credentials = new String(credDecoded, StandardCharsets.UTF_8);
64 | return credentials.split(":", 2);
65 | }
66 | return null;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/com/demo/app/service/UserService.java:
--------------------------------------------------------------------------------
1 | package com.demo.app.service;
2 |
3 | import com.demo.app.model.UserContext;
4 | import org.springframework.stereotype.Service;
5 |
6 | import javax.annotation.PostConstruct;
7 | import java.util.*;
8 |
9 | @Service
10 | public class UserService {
11 |
12 | private final Object mutex = new Object();
13 | private List userContextList = Collections.synchronizedList(new ArrayList<>());
14 |
15 | @PostConstruct
16 | public void init() {
17 |
18 | userContextList.add(new UserContext(1, "Mustafa Kemal", "Atatürk", "mustafa.kemal.ataturk@turkiye.com.tr", "1881", "ADMIN"));
19 | userContextList.add(new UserContext(2, "Hasan Ali", "Yücel", "hasan.ali.yucel@turkiye.com.tr", "1897", "ADMIN"));
20 | }
21 |
22 | public Integer save(UserContext userContext) {
23 |
24 | synchronized (mutex) {
25 | Integer userId = determineMaxUserId();
26 | userContext.setId(userId);
27 | userContextList.add(userContext);
28 | }
29 | return userContext.getId();
30 | }
31 |
32 | public UserContext load(String email) {
33 |
34 | synchronized (mutex) {
35 | return userContextList.stream().filter(u -> u.getEmail().equals(email)).findFirst().orElse(null);
36 | }
37 | }
38 |
39 | public UserContext load(Integer id) {
40 |
41 | synchronized (mutex) {
42 | return userContextList.stream().filter(u -> u.getId().equals(id)).findFirst().orElse(null);
43 | }
44 | }
45 |
46 | private Integer determineMaxUserId() {
47 |
48 | int maxUserId = 1;
49 | UserContext lastUserContext = userContextList.stream().max(Comparator.comparing(UserContext::getId)).orElse(null);
50 | if(lastUserContext != null) {
51 | maxUserId = lastUserContext.getId() + 1;
52 | }
53 | return maxUserId;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/com/demo/app/swagger/Swagger2Configuration.java:
--------------------------------------------------------------------------------
1 | package com.demo.app.swagger;
2 |
3 | import java.util.Arrays;
4 | import java.util.List;
5 |
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.context.annotation.Configuration;
8 | import org.springframework.core.annotation.Order;
9 |
10 | import springfox.documentation.builders.ApiInfoBuilder;
11 | import springfox.documentation.builders.PathSelectors;
12 | import springfox.documentation.builders.RequestHandlerSelectors;
13 | import springfox.documentation.service.ApiInfo;
14 | import springfox.documentation.service.ApiKey;
15 | import springfox.documentation.service.AuthorizationScope;
16 | import springfox.documentation.service.Contact;
17 | import springfox.documentation.service.SecurityReference;
18 | import springfox.documentation.spi.DocumentationType;
19 | import springfox.documentation.spi.service.contexts.SecurityContext;
20 | import springfox.documentation.spring.web.plugins.Docket;
21 |
22 | @Configuration
23 | @Order(2)
24 | public class Swagger2Configuration {
25 |
26 | @Bean
27 | public Docket api() {
28 |
29 | return new Docket(DocumentationType.SWAGGER_2)
30 | .apiInfo(apiEndPointsInfo())
31 | .securityContexts(Arrays.asList(securityContext()))
32 | .securitySchemes(Arrays.asList(apiKey()))
33 | .select()
34 | .apis(RequestHandlerSelectors
35 | .basePackage("com.demo.app.controller"))
36 |
37 | .paths(PathSelectors.any())
38 | .build();
39 | }
40 |
41 | private ApiInfo apiEndPointsInfo() {
42 |
43 | return new ApiInfoBuilder().title("Demo REST API Layer")
44 | .description("Demo REST API Layer")
45 | .contact(new Contact("Batuhan Düzgün", "www.demo.com", "batuhan.duzgun@windowslive.com"))
46 | .license("Apache 2.0")
47 | .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
48 | .version("1.0")
49 | .build();
50 | }
51 |
52 | private ApiKey apiKey() {
53 |
54 | return new ApiKey("JWT", "Authorization", "header");
55 | }
56 |
57 | private SecurityContext securityContext() {
58 |
59 | return SecurityContext.builder().securityReferences(defaultAuth()).build();
60 | }
61 |
62 | private List defaultAuth() {
63 |
64 | AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
65 | AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
66 | authorizationScopes[0] = authorizationScope;
67 | return Arrays.asList(new SecurityReference("JWT", authorizationScopes));
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 |
2 | server.port=9090
3 |
4 | jwt.token.secret=devtech
5 | jwt.token.expiration.duration=18000000
6 |
--------------------------------------------------------------------------------