Skip to content

Commit 005dd31

Browse files
committed
add roles
1 parent fcb6d18 commit 005dd31

File tree

5 files changed

+82
-18
lines changed

5 files changed

+82
-18
lines changed

src/main/java/com/apina/api/config/JwtAuthenticationFilter.java

+26-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import jakarta.servlet.http.HttpServletResponse;
88
import org.slf4j.Logger;
99
import org.slf4j.LoggerFactory;
10+
import org.springframework.beans.factory.annotation.Value;
1011
import org.springframework.context.annotation.Lazy;
1112
import org.springframework.lang.NonNull;
1213
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -27,6 +28,17 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
2728
private final JwtService jwtService;
2829
private final UserDetailsService userDetailsService;
2930

31+
private static final Logger Logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
32+
33+
@Value("${security.jwt.uri}")
34+
private String uri;
35+
36+
@Value("${security.jwt.header}")
37+
private String authorizationHeader;
38+
39+
@Value("${security.jwt.prefix}")
40+
private String prefix;
41+
3042
public JwtAuthenticationFilter(@Lazy JwtService jwtService, @Lazy UserDetailsService userDetailsService, @Lazy HandlerExceptionResolver handlerExceptionResolver) {
3143
this.handlerExceptionResolver = handlerExceptionResolver;
3244
this.jwtService = jwtService;
@@ -35,9 +47,20 @@ public JwtAuthenticationFilter(@Lazy JwtService jwtService, @Lazy UserDetailsSer
3547

3648
@Override
3749
protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException {
38-
final String authHeader = request.getHeader("Authorization");
39-
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
40-
filterChain.doFilter(request, response);
50+
final String authHeader = request.getHeader(authorizationHeader);
51+
final String corsHeader = request.getHeader("Access-Control-Request-Method");
52+
Logger.info("Request: {}, Method {}, AuthHeader: {}", request.getRequestURI(), request.getMethod(), authHeader);
53+
if (corsHeader != null && "OPTIONS".equals(request.getMethod())) {
54+
Logger.info("CORS request detected for options. Setting status to 200.");
55+
response.setStatus(HttpServletResponse.SC_OK);
56+
return;
57+
}
58+
if (authHeader == null || !authHeader.startsWith(prefix + " ")) {
59+
if (request.getMethod().equals("GET") || request.getRequestURI().contains(uri)) {
60+
filterChain.doFilter(request, response);
61+
return;
62+
}
63+
handlerExceptionResolver.resolveException(request, response, null, new Exception("Missing or invalid Authorization header"));
4164
return;
4265
}
4366
try {

src/main/java/com/apina/api/config/SecurityConfig.java

+42-13
Original file line numberDiff line numberDiff line change
@@ -12,40 +12,60 @@
1212
import org.springframework.security.web.SecurityFilterChain;
1313
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
1414
import org.springframework.web.servlet.config.annotation.CorsRegistry;
15+
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
16+
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
1517
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
18+
1619
// SecurityConfig.java
1720
@Configuration
1821
@EnableWebSecurity
22+
@EnableWebMvc
1923
public class SecurityConfig implements WebMvcConfigurer {
2024

2125
private final AuthenticationProvider authenticationProvider;
2226
private final JwtAuthenticationFilter jwtAuthenticationFilter;
2327

24-
private static final String ADMIN = "ADMIN";
25-
private static final String API_GYM = "/api/gym/**";
26-
private static final String API_GYMS = "/api/gyms/**";
27-
private static final String API_USER = "/api/user/**";
28+
@Value("${app.roles.admin}")
29+
private String ADMIN;
30+
31+
@Value("${app.roles.user}")
32+
private String USER;
2833

2934
@Value("${app.cors.allowed-origins}")
3035
private String allowedOrigin;
3136

37+
@Value("${app.cors.allowed-headers}")
38+
private String allowedHeaders;
39+
40+
@Value("${app.cors.allowed-methods}")
41+
private String allowedMethods;
42+
43+
private static final String API_GYM = "/api/gym/**";
44+
private static final String API_GYMS = "/api/gyms/**";
45+
private static final String API_USER = "/api/user/**";
46+
private static final String API_AUTH = "/api/auth/**";
47+
private static final String SWAGGER_UI_HTML = "/swagger-ui.html";
48+
private static final String[] SWAGGER_UI = {"/", "/swagger-ui/**", "/v3/api-docs/**", SWAGGER_UI_HTML, "/webjars/**", "/swagger-resources/**"};
49+
3250
public SecurityConfig(AuthenticationProvider authenticationProvider, JwtAuthenticationFilter jwtAuthenticationFilter) {
3351
this.authenticationProvider = authenticationProvider;
3452
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
3553
}
3654

37-
3855
@Bean
3956
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
4057
http.csrf(AbstractHttpConfigurer::disable)
4158
.authorizeHttpRequests(auth -> auth
42-
.requestMatchers("/api/auth/**","/", "/swagger-ui/**", "/v3/api-docs/**", "/swagger-ui.html", "/webjars/**", "/swagger-resources/**").permitAll()
59+
.requestMatchers(SWAGGER_UI).permitAll()
60+
.requestMatchers(HttpMethod.OPTIONS, "/api/**").permitAll()
61+
.requestMatchers(HttpMethod.GET, API_GYM, API_GYMS, API_USER).permitAll()
62+
.requestMatchers(HttpMethod.POST, API_AUTH).permitAll()
63+
.requestMatchers(HttpMethod.POST, API_GYM).hasAnyRole(ADMIN, USER)
64+
.requestMatchers(HttpMethod.PUT, API_USER).hasAnyRole(ADMIN, USER)
65+
.requestMatchers(HttpMethod.POST, API_GYMS).hasRole(ADMIN)
66+
.requestMatchers(HttpMethod.PUT, API_GYMS, API_GYM).hasRole(ADMIN)
4367
.requestMatchers(HttpMethod.DELETE, API_GYMS, API_GYM, API_USER).hasRole(ADMIN)
44-
.requestMatchers(HttpMethod.POST, API_GYMS, API_GYM).hasRole(ADMIN)
45-
.requestMatchers(HttpMethod.PUT, API_GYMS, API_GYM, API_USER).hasRole(ADMIN)
46-
.requestMatchers(HttpMethod.GET, API_GYMS, API_GYM, API_USER).permitAll()
47-
.anyRequest()
48-
.authenticated())
68+
.anyRequest().fullyAuthenticated())
4969
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
5070
.authenticationProvider(authenticationProvider)
5171
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
@@ -56,9 +76,18 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
5676
public void addCorsMappings(CorsRegistry registry) {
5777
registry.addMapping("/api/**")
5878
.allowedOriginPatterns(allowedOrigin)
59-
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
60-
.allowedHeaders("*")
79+
.allowedMethods(allowedMethods)
80+
.allowedHeaders(allowedHeaders)
6181
.allowCredentials(true);
6282
}
83+
84+
@Override
85+
public void addViewControllers(ViewControllerRegistry registry) {
86+
registry.addRedirectViewController("/", SWAGGER_UI_HTML);
87+
registry.addRedirectViewController("/swagger", SWAGGER_UI_HTML);
88+
registry.addRedirectViewController("/swagger-ui", SWAGGER_UI_HTML);
89+
registry.addRedirectViewController("/swagger-ui/", SWAGGER_UI_HTML);
90+
}
91+
6392
}
6493

src/main/java/com/apina/api/controllers/GymController.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import java.util.List;
1515

1616
import static com.apina.api.util.ControllerUtils.isAdmin;
17+
import static com.apina.api.util.ControllerUtils.isUser;
1718
@RestController
1819
@RequestMapping("/api")
1920
public class GymController {
@@ -29,7 +30,7 @@ public GymController(GymService gymService) {
2930
public GymDTO postGym(@RequestBody GymDTO gymDTO) {
3031
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
3132
LOGGER.info("postGym: {}", authentication);
32-
if (isAdmin(authentication)) {
33+
if (isAdmin(authentication) || isUser(authentication)) {
3334
return gymService.save(gymDTO);
3435
}
3536
return null;

src/main/java/com/apina/api/controllers/UserController.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import java.util.List;
1515

1616
import static com.apina.api.util.ControllerUtils.isAdmin;
17+
import static com.apina.api.util.ControllerUtils.isCurrentUser;
1718
//UserController.java
1819
@RestController
1920
@RequestMapping("/api/user")
@@ -94,7 +95,7 @@ public ResponseEntity<String> deleteAllUsers() {
9495
public ResponseEntity<UserDTO> updateUser(@PathVariable String username) {
9596
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
9697
LOGGER.info("updateUser: {}", authentication);
97-
if (isAdmin(authentication)) {
98+
if (isAdmin(authentication) || isCurrentUser(authentication, username)) {
9899
UserDTO user = userService.findByUsername(username).orElse(null);
99100
if (user != null) {
100101
return ResponseEntity.ok(userService.update(user));

src/main/java/com/apina/api/util/ControllerUtils.java

+10
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,14 @@ public class ControllerUtils {
88
public static boolean isAdmin(Authentication authentication) {
99
return authentication.isAuthenticated() && authentication.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals(ROLE_ADMIN));
1010
}
11+
12+
public static boolean isCurrentUser(Authentication authentication, String username) {
13+
return authentication.isAuthenticated() && authentication.getName().equals(username);
14+
}
15+
16+
public static boolean isUser(Authentication authentication) {
17+
return authentication.isAuthenticated() && authentication.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ROLE_USER"));
18+
}
19+
1120
}
21+

0 commit comments

Comments
 (0)