[Spring Security + JWT] Phần 3 - Đọc JWT và làm một vài api test permission

phần 2 mình đã tạo ra token và làm cái api đăng nhập rồi trả về token. ở phần này mình sẽ đọc thông tin từ cái token đó xử lý nó và làm thử cái api test quyền truy cập nhé :smile:

Chiến luôn thôi :innocent:

Tạo method đọc JWT này

private JWTClaimsSet getClaimsFromToken(String token) {
        JWTClaimsSet claims = null;
        try {
            SignedJWT signedJWT = SignedJWT.parse(token);
            JWSVerifier verifier = new MACVerifier(SECRET.getBytes());
            if (signedJWT.verify(verifier)) {
                claims = signedJWT.getJWTClaimsSet();
            }
        } catch (ParseException | JOSEException e) {
            logger.error(e.getMessage());
        }
        return claims;
    }

    public UserPrincipal getUserFromToken(String token) {
        UserPrincipal user = null;
        try {
            JWTClaimsSet claims = getClaimsFromToken(token);
            if (claims != null && isTokenExpired(claims)) {
                JSONObject jsonObject = (JSONObject) claims.getClaim(USER);
                user = new ObjectMapper().readValue(jsonObject.toJSONString(), UserPrincipal.class);
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        return user;
    }

    private Date getExpirationDateFromToken(JWTClaimsSet claims) {
        return claims != null ? claims.getExpirationTime() : new Date();
    }

    private boolean isTokenExpired(JWTClaimsSet claims) {
        return getExpirationDateFromToken(claims).after(new Date());
    }
  • Đây nhé trong method getClaimsFromToken ta sẽ lấy ra JWTClaimsSet, trong đây phải có đúng chuỗi SECRET đã tạo ra token mới lấy ra được JWTClaimsSet.
  • Method getUserFromToken ta sẽ lấy ra cái thằng UserPrincipal hôm trước đã tạo và cho vào trong token :blush:

Method lấy token trong database

TokenRepository

Token findByToken(String token);

TokenService

Token findByToken(String token);

TokenService

@Override
public Token findByToken(String token) {
    return tokenRepository.findByToken(token);
}

Tạo class filter

@Component
public class JwtRequestFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private TokenService verificationTokenService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        final String authorizationHeader = request.getHeader("Authorization");

        UserPrincipal user = null;
        Token token = null;
        if (StringUtils.hasText(authorizationHeader) && authorizationHeader.startsWith("Token ")) {
            String jwt = authorizationHeader.substring(6);
            user = jwtUtil.getUserFromToken(jwt);
            token = verificationTokenService.findByToken(jwt);
        }

        if (null != user && null != token && token.getTokenExpDate().after(new Date())) {
            Set<GrantedAuthority> authorities = new HashSet<>();
            user.getAuthorities().forEach(p -> authorities.add(new SimpleGrantedAuthority((String) p)));
            UsernamePasswordAuthenticationToken authentication =
                    new UsernamePasswordAuthenticationToken(user, null, authorities);
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }

        filterChain.doFilter(request, response);
    }

}
  • Ở đây mình extend từ OncePerRequestFilter thằng này sẽ chỉ thực hiện một lần filter trong mỗi request.
  • Trong đây mình sẽ kiểm tra trong header của mỗi request có thằng Authorization với giá trị bắt đầu là Token(ví dụ: Token abcdaw123cas.asdawe...) thì mình mới xử lý.
  • Sau khi kiểm tra token hợp lệ, thì mình sẽ phải set vào trong SecurityContextHolder.getContext().setAuthentication(). Đây chính là cái phần mà chỗ set vào của chỗ mình bảo UserPrincipal có thể lấy được bất kỳ đâu trong ứng dụng, là nó được tạo dữ liệu từ đây.

Thêm filter security config

@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtRequestFilter jwtRequestFilter;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class)
                .csrf().disable();
    }
}
  • @EnableGlobalMethodSecurity(prePostEnabled = true) cái này sẽ giúp mình có thể kiểm soát security đến từng phương thức. Ở đây prePostEnabled = true mình sẽ sử dụng được 2 annotation @PreAuthorize@PostAuthorize để phân quyền.

Thêm api test permission

@GetMapping("/hello")
@PreAuthorize("hasAnyAuthority('USER_READ')")
public ResponseEntity hello(){
    return ResponseEntity.ok("hello");
}

Test thử api

mọi thứ đều chuẩn nó sẽ thế này
alt text
đây là khi token sai
alt text
đây là không có quyền vào role
alt text

Thêm 2 annotation @CreatedBy@LastModifiedBy

Thêm vào BaseEntity

@CreatedBy
private Long createdBy;

@LastModifiedBy
private Long updatedBy;

Class cái gì đó AuditorAware

@Component
public class SpringSecurityAuditorAware implements AuditorAware<Long> {

    @Override
    public Optional<Long> getCurrentAuditor() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            return null;
        }
        if (authentication.getPrincipal()=="anonymousUser"){
            return Optional.of(0l);
        }
        return Optional.of(((UserPrincipal) authentication.getPrincipal()).getUserId());
    }

}
  • mình đặt tên là SpringSecurityAuditorAware vì mình không biết đặt tên gì nữa :D. Đó giờ là 2 cái annotation kia đã hoạt động được rồi.

Tổng kết

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

hunghh.dev

8 bài viết.
7 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
7 0
Xin chào các bạn đọc, trong seri này mình dự định sẽ chia sẻ cách dùng spring security để phân quyền trong web service, cách đọc ghi một JWT, rồi t...
hunghh.dev viết 7 tháng trước
7 0
White
6 1
Restful api Rest (Representational State Transfer) hiểu nôm na nó là một kiểu kiến trúc được dùng để giao tiếp giữa các máy tính, được truyền tải...
hunghh.dev viết 6 tháng trước
6 1
White
3 0
Ở (Link) mình đã tạo một số model và tạo thử một api register, ở phần này mình sẽ hướng dẫn các bạn tạo một chuỗi JWT và khi login sẽ chả về cái ch...
hunghh.dev viết 7 tháng trước
3 0
Bài viết liên quan
White
0 0
Giới thiệu Trong bài hôm nay chúng ta sẽ tìm hiểu cách handle request POST của Spring Boot. Trước đó, bạn nên biết 1. 「Spring Boot 8」Tạo Web He...
https://loda.me viết hơn 1 năm trước
0 0
White
4 0
I used Spring boot, Hibernate few times back then at University, I'v started using it again recently. In this (Link), I want to check how Spring J...
Rey viết hơn 1 năm trước
4 0
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
8 bài viết.
7 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!