Skip to content

Commit

Permalink
Merge pull request #265 from sixwaaaay/service
Browse files Browse the repository at this point in the history
security update
  • Loading branch information
sixwaaaay authored Jul 24, 2024
2 parents c0fa911 + f67a25b commit db478f4
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 57 deletions.
4 changes: 4 additions & 0 deletions graal/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@
<artifactId>resilience4j-all</artifactId>
<version>${resilience4jVersion}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>

<build>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2023-2024 sixwaaaay.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.sixwaaaay.sharingcomment.config;

import io.sixwaaaay.sharingcomment.util.TokenParser;
import lombok.SneakyThrows;
import org.springframework.context.annotation.Bean;
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.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
public class SecurityConfig {

@Bean
UserDetailsService emptyDetailsService() {
return username -> {
throw new UsernameNotFoundException("no local users, only JWT tokens allowed");
};
}


@Bean
@SneakyThrows
public SecurityFilterChain filterChain(HttpSecurity http, TokenParser tokenParser) {
http.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(
HttpMethod.POST,
"/comments",
"/comments/action/like/*"
).hasAuthority("BASIC_USER")
.requestMatchers(HttpMethod.DELETE,
"/comments/*",
"/comments/action/like/*"
).hasAuthority("BASIC_USER")
.requestMatchers(
HttpMethod.GET,
"/comments/main",
"/comments/reply"
).permitAll()
).addFilterBefore(new ServiceInterceptor(tokenParser), UsernamePasswordAuthenticationFilter.class)
.sessionManagement(smc -> smc.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.csrf(AbstractHttpConfigurer::disable);
return http.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,37 @@

package io.sixwaaaay.sharingcomment.config;

import io.sixwaaaay.sharingcomment.request.Principal;
import io.sixwaaaay.sharingcomment.util.TokenParser;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.List;
import java.util.Optional;


@Component
@AllArgsConstructor
public class ServiceInterceptor implements HandlerInterceptor {
public class ServiceInterceptor extends OncePerRequestFilter {

private final TokenParser tokenParser;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
var token = request.getHeader("Authorization");
tokenParser.parse(token);
return true;
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
var authorization = tokenParser.parse(request.getHeader("Authorization"));
if (authorization.isPresent()) {
var authentication = new UsernamePasswordAuthenticationToken(authorization.get(), null, List.of(new SimpleGrantedAuthority("BASIC_USER")));
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(request, response);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import io.sixwaaaay.sharingcomment.domain.ReplyResult;
import io.sixwaaaay.sharingcomment.request.CommentRequest;
import io.sixwaaaay.sharingcomment.request.Principal;
import io.sixwaaaay.sharingcomment.request.error.NoUserExitsError;
import io.sixwaaaay.sharingcomment.service.CommentService;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
Expand All @@ -30,8 +29,6 @@
import java.time.ZoneOffset;
import java.util.Optional;

import static io.sixwaaaay.sharingcomment.util.TokenParser.principal;

@RestController
@RequestMapping("/comments")
@AllArgsConstructor
Expand All @@ -52,7 +49,7 @@ public CommentResult getMainCommentList(
@RequestParam(value = "page") Optional<Long> id,
@RequestParam(value = "size", defaultValue = "10") Integer size
) {
var userId = principal.get().map(Principal::getId).orElse(0L);
var userId = Principal.currentUserId();
return commentService.getMainCommentList(belongTo, id.orElse(Long.MAX_VALUE), size, userId);
}

Expand All @@ -69,7 +66,7 @@ public ReplyResult getReplyCommentList(
@RequestParam(value = "page", defaultValue = "0") long id,
@RequestParam(value = "size", defaultValue = "10") Integer size
) {
var userId = principal.get().map(Principal::getId).orElse(0L);
var userId = Principal.currentUserId();
return commentService.getReplyCommentList(belongTo, replyTo, id, size, userId);
}

Expand All @@ -81,8 +78,8 @@ public ReplyResult getReplyCommentList(
@PostMapping
public Comment createComment(@Valid @RequestBody CommentRequest request) {
var comment = new Comment();
var id = principal.get().map(Principal::getId).orElseThrow(NoUserExitsError::supply);
comment.setUserId(id); // throw exception if principal is empty
var id = Principal.currentUserId();
comment.setUserId(id);
comment.setBelongTo(request.getBelongTo());
comment.setContent(request.getContent());
comment.setReferTo(request.getReferTo());
Expand All @@ -99,9 +96,9 @@ public void deleteComment(
@PathVariable("id") Long id,
@RequestBody CommentRequest request
) {
var userId = principal.get().map(Principal::getId).orElseThrow(NoUserExitsError::supply);
var userId = Principal.currentUserId();
var comment = new Comment();
comment.setUserId(userId); // throw exception if principal is empty
comment.setUserId(userId);
comment.setId(id);
comment.setReplyTo(request.getReplyTo());
commentService.deleteComment(comment);
Expand All @@ -115,7 +112,7 @@ public void deleteComment(
@PostMapping("/action/like/{id}")
public void voteComment(
@PathVariable long id) {
var userId = principal.get().map(Principal::getId).orElseThrow(NoUserExitsError::supply);
var userId = Principal.currentUserId();
commentService.voteComment(userId, id);
}

Expand All @@ -127,7 +124,7 @@ public void voteComment(
@DeleteMapping("/action/like/{id}")
public void cancelVoteComment(
@PathVariable long id) {
var userId = principal.get().map(Principal::getId).orElseThrow(NoUserExitsError::supply);
var userId = Principal.currentUserId();
commentService.cancelVoteComment(userId, id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@

package io.sixwaaaay.sharingcomment.request;

import io.sixwaaaay.sharingcomment.request.error.NoUserExitsError;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;

/**
* The Principal class represents the principal user in the system.
Expand All @@ -38,4 +41,29 @@ public class Principal {
* The token of the principal user.
*/
private String token;

/**
* The current token of the principal user.
* @return the current token of the principal user.
*/
public static String currentToken(){
if (SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof Principal principal) {
return principal.getToken();
} else {
return null;
}
}

/**
* The current user ID of the principal user.
* @return the current user ID of the principal user.
*/
public static long currentUserId(){
if (SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof Principal principal) {
return principal.getId();
} else if (SecurityContextHolder.getContext().getAuthentication() instanceof AnonymousAuthenticationToken) {
return 0;
}
throw NoUserExitsError.supply();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static io.sixwaaaay.sharingcomment.util.TokenParser.principal;
import static java.util.function.Function.identity;

@Service
Expand Down Expand Up @@ -177,7 +176,7 @@ public void cancelVoteComment(Long userId, Long commentId) {
*/
private void composeSingleComment(Comment comment) {
if (enableUser) {
var token = principal.get().map(Principal::getToken).orElse("");
var token = Principal.currentToken();
var user = userClient.getUser(comment.getUserId(), token);
comment.setUser(user.getUser());
}
Expand Down Expand Up @@ -217,7 +216,7 @@ private Map<Long, User> composeCommentAuthor(List<Comment> comments) {
// get user id list
var userList = flatComments(comments).map(Comment::getUserId).distinct().toList();
// fetch user info
var token = principal.get().map(Principal::getToken).orElse("");
var token = Principal.currentToken();
var users = userClient.getManyUser(userList, token);
// covert to map
return users.getUsers().stream().collect(Collectors.toMap(User::getId, identity()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@
public class TokenParser {
private final JwtParser jwtParser;

public static ThreadLocal<Optional<Principal>> principal = new ThreadLocal<>();

public TokenParser(@Value("${jwt.secret}") String secret) {
var secretKey = Keys.hmacShaKeyFor(secret.getBytes());
jwtParser = Jwts.parserBuilder()
Expand All @@ -45,7 +43,6 @@ public TokenParser(@Value("${jwt.secret}") String secret) {
public Optional<Principal> parse(String token) {
var PREFIX = "Bearer ";
if (token == null || token.isEmpty() || !token.startsWith(PREFIX)) {
principal.set(Optional.empty());
return Optional.empty();
}

Expand All @@ -54,7 +51,6 @@ public Optional<Principal> parse(String token) {
var name = claimsJws.getBody().get("name", String.class);
var id = claimsJws.getBody().get("id", String.class);
var value = new Principal(name, Long.parseLong(id), token);
principal.set(Optional.of(value));
return Optional.of(value);
}

Expand Down

0 comments on commit db478f4

Please sign in to comment.