_Xem phần 1 tại đây

Xem bài viết gốc tại đây_

Authorization với Spring Security

Cho tới giờ chúng ta mới chỉ nói về authentication, ví dụ: kiểm tra username và password.

Bây giờ chúng ta hãy xem xét quyền, hay đúng hơn là vai trò và quyền hạn trong Spring Security.

Authorization là gì?

Hãy xem trang web thương mại điện tử điển hình của bạn. Nó có thể bao gồm các phần sau:

  • Chính trang web bán hàng. Giả sử URL của nó là <em style="box-sizing:border-box">www.youramazinshop.com</em>.

  • Có thể là một khu vực dành cho các đại lý bán hàng, nơi họ có thể đăng nhập và xem một khách hàng gần đây đã mua những gì hoặc bưu kiện của họ ở đâu. URL của nó có thể là <em style="box-sizing:border-box">www.youramazinshop.com/callcenter</em>.

  • Một khu vực quản trị riêng biệt, nơi quản trị viên có thể đăng nhập và quản lý các đại lý bán hàng hoặc các khía cạnh kỹ thuật khác (như chủ đề, hiệu suất, v.v.) của web bán hàng. URL của nó có thể là <em style="box-sizing:border-box">www.youramazinshop.com/admin</em>.

Điều này có những ý nghĩa sau đây, vì chỉ authenticate thôi thì không còn đủ nữa:

  • Một khách hàng rõ ràng sẽ không thể truy cập vào đại lý trung tâm hoặc khu vực quản trị. Anh/cô ta chỉ được phép mua sắm trong trang web.

  • Một đại lý trung tâm sẽ không thể truy cập vào khu vực quản trị.

  • Trong khi đó, quản trị viên có thể truy cập web bán hàng, khu vực các đại lý trung tâm và khu vực quản trị.

Nói một cách đơn giản, bạn muốn cho phép các quyền truy cập khác nhau cho những user khác nhau, tùy thuộc vào quyền hạn hoặc vai trò của họ .

Authorities là gì? Vai trò (roles) là gì?

Đơn giản thôi:

  • Một authority (ở dạng đơn giản nhất) chỉ là một chuỗi, nó có thể là bất kỳ thứ gì như: user, ADMIN, ROLE_ADMIN hoặc 53cr37_r0l3.

  • Một vai trò là một authority có tiền tố <em style="box-sizing:border-box">ROLE_</em>. Vì vậy, một vai trò được gọi <em style="box-sizing:border-box">ADMIN </em> cũng giống như một authority được gọi <em style="box-sizing:border-box">ROLE_ADMIN</em>.

Sự phân biệt giữa vai trò và quyền hạn chỉ đơn giản là khái niệm và vì thế thường khiến những người mới tham gia Spring Security bối rối.

Tại sao có sự phân biệt giữa vai trò và quyền hạn?

Thành thật mà nói, tôi đã đọc tài liệu Spring Security cũng như một vài bài StackOverflow có liên quan đến câu hỏi này và tôi vẫn không thể cung cấp cho bạn một câu trả lời dứt khoát.

GrantedAuthority là gì? SimpleGrantedAuthority là gì?

Tất nhiên, Spring Security không cho phép bạn trốn tránh bằng cách chỉ sử dụng Strings. Có một class Java đại diện cho String authority của bạn, một class phổ biến chính là SimpleGrantedAuthority.

public final class SimpleGrantedAuthority implements GrantedAuthority {

private final String role;

@Override
public String getAuthority() {
    return role;
}
}

(Lưu ý: Cũng có các class authority khác, cho phép bạn lưu trữ các object bổ sung cùng với string của bạn, tôi sẽ không trình bày chúng ở đây. Hiện tại, chúng ta sẽ chỉ sử dụng SimpleGrantedAuthority.)

1. UserDetailsService: Nơi lưu trữ và get authorities?

Giả sử bạn đang lưu trữ user trong ứng dụng của mình (hãy nhớ lại UserDetailsService), bạn sẽ có một bảng User .

Bây giờ, bạn chỉ cần thêm một cột có tên “authorities” vào đó. Đối với bài viết này, tôi đã chọn một cột String đơn giản ở đây, mặc dù nó có thể chứa nhiều giá trị được phân tách bằng dấu phẩy. Ngoài ra, tôi cũng có thể có một bảng AUTHORITIES hoàn toàn tách biệt, nhưng đối với phạm vi của bài viết này thế này là đủ.

Lưu ý: Trở lại với Authorities là gì? Vai trò là gì?: Bạn save các authority, tức là String, vào cơ sở dữ liệu. Rất có thể các authority này bắt đầu với tiền tố ROLE_, vì vậy, xét về mặt Spring Security, các authority này cũng chính là các vai trò.

usernamepasswordauthorities
john@doe.com{bcrypt}…​ROLE_ADMIN
my@callcenter.com{sha256}…​ROLE_CALLCENTER

Bảng 2. Bảng Users với Permissions

Điều duy nhất còn lại phải làm là điều chỉnh UserDetailsService của bạn để read trong cột authorities đó.

public class MyDatabaseUserDetailsService implements UserDetailsService {

UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
     User user = userDao.findByUsername(username);
     List<SimpleGrantedAuthority> grantedAuthorities = user.getAuthorities().map(authority -> new SimpleGrantedAuthority(authority)).collect(Collectors.toList()); // (1)
     return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), grantedAuthorities); // (2)
}

}
  1. Bạn chỉ cần ánh xạ bất cứ thứ gì bên trong cột database của mình vào danh sách SimpleGrantedAuthority là xong.

  2. Lần nữa, chúng ta đang sử dụng implementation UserDetails cơ bản của Spring Security ở đây. Bạn cũng có thể sử dụng class của riêng mình triển khai UserDetails và thậm chí có thể không cần phải ánh xạ sau đó.

2. AuthenticationManager: Lưu trữ và get các authorities ở đâu?

Khi user đến từ một ứng dụng của bên thứ ba, như Atlassian Cloud, bạn sẽ cần tìm hiểu xem họ đang sử dụng khái niệm gì để hỗ trợ các authorities. Atlassian Crowd có các khái niệm về “vai trò”, nhưng không dùng khái niệm này để ủng hộ “nhóm”.

Vì vậy, tùy thuộc vào sản phẩm thực tế bạn đang sử dụng, bạn cần ánh xạ đến Spring Security authority, trong AuthenticationProvider của bạn.

public class AtlassianCrowdAuthenticationProvider implements AuthenticationProvider {

    Authentication authenticate(Authentication authentication)
            throws AuthenticationException {
        String username = authentication.getPrincipal().toString();
        String password = authentication.getCredentials().toString();

        atlassian.crowd.User user = callAtlassianCrowdRestService(username, password); // (1)
        if (user == null) {
            throw new AuthenticationException("could not login");
        }
        return new UserNamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), mapToAuthorities(user.getGroups())); // (2)
    }
            // other method ignored
}
  1. Lưu ý: Đây không phải là code Atlassian Crowd thực tế , nhưng vẫn phục vụ mục đích của nó. Bạn authenticate với một dịch vụ REST và lấy lại object User JSON, object này sau đó được chuyển đổi thành object atlassian.crowd.User.

  2. User đó có thể là thành viên của một hoặc nhiều nhóm, ở đây chỉ là những strings. Bạn sau đó có thể đơn giản chỉ cần ánh xạ các nhóm này với “SimpleGrantedAuthority” của Spring.

Xem lại WebSecurityConfigurerAdapter dành cho authorities

Cho đến nay, chúng ta đã nói nhiều về việc lưu trữ và truy xuất các authorities cho User đã authenticate trong Spring Security. Nhưng làm thế nào để bạn bảo vệ các URL với các authority khác nhau với DSL của Spring Security? Đơn giản thôi:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
    .authorizeRequests()
      .antMatchers("/admin").hasAuthority("ROLE_ADMIN") // (1)
      .antMatchers("/callcenter").hasAnyAuthority("ROLE_ADMIN", "ROLE_CALLCENTER") // (2)
      .anyRequest().authenticated() // (3)
      .and()
    .formLogin()
      .and()
    .httpBasic();
}
}
  1. Để truy cập khu vực <em style="box-sizing:border-box">/admin</em>, bạn (tức là user) cần được authenticate  có authority (một string đơn giản) ROLE_ADMIN.

  2. Để truy cập khu vực <em style="box-sizing:border-box">/callcenter</em>, bạn cần phải được authenticate  có authority ROLE_ADMIN HOẶC ROLE_CALLCENTER.

  3. Đối với bất kỳ yêu cầu nào khác, bạn không cần vai trò cụ thể nhưng vẫn cần được authenticate.

Lưu ý rằng đoạn code (1,2) trên tương đương với code sau:

http.authorizeRequests()
    .antMatchers("/admin").hasRole("ADMIN") // (1)
    .antMatchers("/callcenter").hasAnyRole("ADMIN", "CALLCENTER") // (2)
  1. Thay vì gọi “hasAuthority”, bây giờ bạn gọi “hasRole”. Ghi chú : Spring Security sẽ tìm kiếm một authority được gọi <em style="box-sizing:border-box">ROLE_ADMIN </em> trên user được authenticate.

  2. Thay vì gọi “hasAnyAuthority”, bây giờ bạn gọi “hasAnyRole”. Ghi chú : Spring Security sẽ tìm kiếm một authority được gọi <em style="box-sizing:border-box">ROLE_ADMIN </em> hoặc <em style="box-sizing:border-box">ROLE_CALLCENTER </em> trên user đã authenticate.

hasAccess và SpEL

Cuối cùng cũng không kém phần quan trọng, cách mạnh nhất để cấu hình authorization là với method access . Nó cho phép bạn chỉ định khá nhiều biểu thức SpEL.

http.authorizeRequests()
    .antMatchers("/admin").access("hasRole('admin').
and hasIpAddress('192.168.1.0/24')
and @myCustomBean.checkAccess(authentication,request)") // (1)
  1. Bạn đang kiểm tra xem liệu user có ROLE_ADMIN, với IP address cụ thể cũng như một bean thông thường.

Để có cái nhìn tổng quan đầy đủ về những gì có thể làm được với Spring’s Expression-Based Access Control, hãy xem tài liệu chính thức .

Các biện pháp bảo vệ khỏi bị khai thác

Có một loạt các cuộc tấn công phổ biến mà Spring Security giúp bạn chống lại. Bắt đầu với các cuộc tấn công theo thời gian (tức là Spring Security sẽ luôn băm password được cung cấp khi login, ngay cả khi user không tồn tại) và kết thúc với các biện pháp bảo vệ chống lại các cuộc tấn công kiểm soát bộ nhớ cache, đánh hơi nội dung, kích hoạt nhấp chuột, viết mã chéo trang web và còn nhiều nữa.

Không thể đi sâu vào chi tiết của từng cuộc tấn công trong phạm vi của bài giảng này. Do đó, chúng ta sẽ chỉ xem xét một biện pháp bảo vệ khiến hầu hết những người mới sử dụng Spring Security đau đầu nhất: Cross-Site-Request-Forgery.

Cross-Site-Request-Forgery: CSRF

Nếu bạn hoàn toàn mới sử dụng CSRF, bạn có thể muốn xem video YouTube này để theo kịp. Tuy nhiên, cách giải quyết nhanh chóng là, Spring Security mặc định bảo vệ mọi request POST (hoặc PUT / DELETE / PATCH) với một CSRF token hợp lệ.

Điều đó có nghĩa là gì?

CSRF & HTML được hiển thị phía máy chủ

Hãy tưởng tượng một form chuyển khoản ngân hàng hay bất kỳ form nào (như form đăng nhập) cho vấn đề đó, được @Controllers của bạn hiển thị với sự trợ giúp của công nghệ tạo template như Thymeleaf hoặc Freemarker.

<form action="/transfer" method="post">  <!-- 1 -->
<input type="text" name="amount"/>
<input type="text" name="routingNumber"/>
<input type="text" name="account"/>
<input type="submit" value="Transfer"/>
</form>

Với Spring Security được bật, bạn sẽ không thể submit form đó nữa . Bởi vì CSRFFilter của Spring Security đang tìm kiếm một parameter ẩn bổ sung trên bất kỳ request POST (PUT / DELETE) nào: cái gọi là CSRF token.

Theo mặc định, nó cứ tạo ra một token như vậy cho mỗi một HTTP session và lưu trữ ở đó. Và bạn cần đảm bảo inject nó vào bất kỳ form HTML nào của mình.

CSRF tokens & Thymeleaf

Vì Thymeleaf tích hợp tốt với Spring Security (khi được sử dụng cùng với Spring Boot), bạn chỉ cần thêm đoạn code sau vào bất kỳ form nào và bạn sẽ nhận được token tự động được inject, từ session, vào form của bạn. Thậm chí tốt hơn, nếu bạn đang sử dụng “th: action” cho form của mình, Thymeleaf sẽ tự động inject field ẩn đó cho bạn mà không cần phải thực hiện theo cách thủ công.

<form action="/transfer" method="post">  <!-- 1 -->
<input type="text" name="amount"/>
<input type="text" name="routingNumber"/>
<input type="text" name="account"/>
<input type="submit" value="Transfer"/>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
</form>

<!-- OR -->

<form th:action="/transfer" method="post">  <!-- 2 -->
<input type="text" name="amount"/>
<input type="text" name="routingNumber"/>
<input type="text" name="account"/>
<input type="submit" value="Transfer"/>
</form>
  1. Ở đây, chúng ta đang add parameter CSRF theo cách thủ công.

  2. Ở đây, chúng ta đang sử dụng hỗ trợ form của Thymeleaf.

Lưu ý: Để biết thêm thông tin về hỗ trợ CSRF của Thymeleaf, hãy xem tài liệu chính thức .

CSRF & Các thư viện template khác

Tôi không thể trình bày tất cả các thư viện template trong phần này, nhưng phương sách cuối cùng là bạn luôn có thể đưa CSRFToken vào bất kỳ method @Controller nào của mình và chỉ cần add nó vào model để render nó thành một view hoặc truy cập trực tiếp dưới dạng request attribute HttpServletRequest .

@Controller
public class MyController {
@GetMaping("/login")
public String login(Model model, CsrfToken token) {
    // the token will be injected automatically
    return "/templates/login";
}
}

CSRF & React hay Angular

Mọi thứ có một chút khác biệt đối với ứng dụng Javascript, như ứng dụng single page React hoặc Angular. Đây là những gì bạn cần làm:

  1. Cấu hình cho Spring Security để sử dụng CookieCsrfTokenRepository, hệ thống này sẽ đưa CSRFToken vào một cookie “XSRF-TOKEN” (và gửi cookie đó đến trình duyệt).

  2. Làm cho ứng dụng Javascript của bạn nhận giá trị cookie đó và gửi nó dưới dạng “X-XSRF-TOKEN” header với mọi request POST (/ PUT / PATCH / DELETE).

Để có ví dụ đầy đủ về React copy-and-paste, hãy xem bài đăng tuyệt vời trên blog này: https://developer.okta.com/blog/2018/07/19/simple-crud-react-and-spring-boot .

Tắt CSRF

Nếu bạn chỉ cung cấp một REST API vô định hình nơi mà sự bảo vệ CSRF không có ý nghĩa gì, bạn sẽ vô hiệu hóa hoàn toàn bảo vệ CSRF. Đây là cách để bạn làm điều đó:

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable();
}
}

Spring Integrations

Spring Security & Spring Framework

Trong hầu hết bài viết này, bạn mới chỉ chỉ định cấu hình bảo mật trên tầng web của ứng dụng của bạn. Bạn đã bảo vệ các URL nhất định bằng antMatcher hoặc regexMatchers bằng DSL của WebSecurityConfigurerAdapter. Đó là một cách tiếp cận hoàn toàn ổn và tiêu chuẩn để bảo mật.

Ngoài việc bảo vệ tầng web của bạn, còn có ý tưởng “bảo vệ theo chiều sâu (defense in depth)”. Điều đó có nghĩa là ngoài việc bảo vệ URL, bạn có thể bảo vệ chính tầng xử lý logic của mình. Hay @Controllers, @Components, @Services hoặc thậm chí @Repositories của bạn. Nói ngắn gọn là các bean trong ứng dụng Spring của bạn.

Method security

Cách tiếp cận đó được gọi <em style="box-sizing:border-box">method security </em> và hoạt động thông qua các annotation mà về cơ bản bạn có thể đặt trên bất kỳ public method nào trong Spring bean của mình. Bạn cũng cần enable method security một cách rõ ràng bằng cách đặt annotation @EnableGlobalMethodSecurity trên ApplicationContextConfiguration của bạn.

@Configuration
@EnableGlobalMethodSecurity(
prePostEnabled = true, // (1)
securedEnabled = true, // (2)
jsr250Enabled = true) // (3)
public class YourSecurityConfig extends WebSecurityConfigurerAdapter{
}
  1. Thuộc tính prePostEnabled cho phép hỗ trợ các annotation <em style="box-sizing:border-box">@PreAuthorize </em> và <em style="box-sizing:border-box">@PostAuthorize </em> của Spring. Hỗ trợ có nghĩa là Spring sẽ bỏ qua chú thích này nếu bạn không đặt nó thành true.

  2. Thuộc tính secureEnabled cho phép hỗ trợ annotion <em style="box-sizing:border-box">@Secured</em>. Hỗ trợ ở đây có nghĩa là Spring sẽ bỏ qua chú thích này nếu bạn không đặt nó thành true.

  3. Thuộc tính jsr250Enabled cho phép hỗ trợ annotation <em style="box-sizing:border-box">@RolesAllowed</em>. Hỗ trợ ở đây có nghĩa là Spring sẽ bỏ qua chú thích này nếu bạn không đặt thành true.

Sự khác biệt giữa @PreAuthorize, @Secured và @RolesAllowed là gì?

@Secured và @RolesAllowed về cơ bản giống nhau, mặc dù @Secured là một annotation dành riêng cho Spring đi kèm với dependency spring-security-core và @RolesAllowed là một annotation được chuẩn hóa, nằm trong dependency javax.annotation-api. Cả hai annotation đều lấy một string authority/role làm value.

@ PreAuthorize / @ PostAuthorize cũng là các annotation cụ thể (mới hơn) của Spring và mạnh hơn các annotation ở trên, vì chúng có thể chứa không chỉ các authority/role mà còn chứa bất kỳ biểu thức SpEL valid nào .

Cuối cùng, tất cả các annotation này sẽ phát sinh <em style="box-sizing:border-box">AccessDeniedException</em> nếu bạn thử truy cập một protected method với authority / role không đủ.

Vì thế, chúng ta hãy cùng xem cách các annotation này hoạt động.

@Service
public class SomeService {

    @Secured("ROLE_CALLCENTER") // (1)
    // == @RolesAllowed("ADMIN")
    public BankAccountInfo get(...) {

    }

    @PreAuthorize("isAnonymous()") // (2)
    // @PreAuthorize("#contact.name == principal.name")
    // @PreAuthorize("ROLE_ADMIN")
    public void trackVisit(Long id);

    }
}
  1. Như đã đề cập, @Secured có authority/role làm tham số. @RolesAllowed cũng tương tự như vậy. Lưu ý : Hãy nhớ rằng <em style="box-sizing:border-box">@RolesAllowed("ADMIN")</em> sẽ check một authority được cấp <em style="box-sizing:border-box">ROLE_ADMIN</em>.

  2. Như đã đề cập, @PreAuthorize ngoài chấp nhận các authorities còn có bất kỳ biểu thức SpEL valid nào. Đối với danh sách các biểu thức security tích hợp sẵn phổ biến như <em style="box-sizing:border-box">isAnonymous()</em>, thay vì viết các biểu thức SpEL của riêng bạn, hãy xem tài liệu chính thức .

Tôi nên sử dụng annotation nào?

Đây chủ yếu là vấn đề về tính đồng nhất, không cần quá ràng buộc bản thân vào các API dành riêng cho Spring.

Nếu sử dụng @Secured, hãy kiên trì sử dụng và đừng nhảy sang @RolesAllowed trong 28% các bean khác của bạn để cố gắng chuẩn hóa.

Để bắt đầu, bạn có thể sử dụng luôn @Secured và chuyển sang @PreAuthorize ngay khi có nhu cầu.

Spring Security & Spring Web MVC

Đối với việc tích hợp với Spring WebMVC, Spring Security cho phép bạn thực hiện một số việc sau:

  1. Ngoài antMatchers và regexMatchers, bạn cũng có thể sử dụng mvcMatchers. Sự khác biệt là, trong khi antMatchers và regexMatchers về cơ bản để match các chuỗi URI với các ký tự đại diện, mvcMatchers hoạt động giống hệt như @RequestMappings.

  2. Inject principal hiện đã được authenticate của bạn vào method @Controller / @RestController.

  3. Inject CSRFToken session hiện tại của bạn vào một method @Controller / @RestController.

  4. Handle chính xác bảo mật để xử lý request không đồng bộ .

@Controller
public class MyController {

    @RequestMapping("/messages/inbox")
    public ModelAndView findMessagesForUser(@AuthenticationPrincipal CustomUser customUser, CsrfToken token) {  // (1) (2)

    // .. find messages for this user and return them ...
    }
}
  1. @AuthenticationPrincipal sẽ inject một principal nếu user được authenticate hoặc null nếu không có user nào được authenticate. Principal này là object đến từ UserDetailsService / AuthenticationManager của bạn!

  2. Hoặc bạn có thể inject CSRFToken session hiện tại vào từng method.

Nếu bạn không sử dụng annotation @AuthenticationPrincipal, bạn sẽ phải tự mình tìm principal, thông qua SecurityContextHolder. Một kỹ thuật thường thấy trong di sản của các ứng dụng Spring Security.

@Controller
public class MyController {

    @RequestMapping("/messages/inbox")
    public ModelAndView findMessagesForUser(CsrfToken token) {
         SecurityContext context = SecurityContextHolder.getContext();
         Authentication authentication = context.getAuthentication();

         if (authentication != null && authentication.getPrincipal() instanceof UserDetails) {
             CustomUser customUser = (CustomUser) authentication.getPrincipal();
             // .. find messages for this user and return them ...
         }

         // todo
    }
}

Spring Security & Spring Boot

Spring Boot thực sự chỉ cấu hình trước Spring Security cho bạn bất cứ khi nào bạn thêm dependecy spring-boot-starter-security vào dự án Spring Boot của mình.

Ngoài ra, tất cả các cấu hình security đều được thực hiện với các khái niệm Spring Security đơn giản (hãy nhớ: WebSecurityConfigurerAdapter, các quy tắc authentication & authorization), không liên quan gì đến Spring Boot.

Vì vậy, mọi thứ bạn đọc trong phần hướng dẫn này áp dụng 1: 1 để sử dụng Spring Security với Spring Boot. Và nếu bạn không hiểu rõ về Security, đừng mong hiểu đúng cách cả hai công nghệ hoạt động cùng nhau.

Spring Security & Thymeleaf

Spring Security tích hợp tốt với Thymeleaf. Nó cung cấp một phương ngữ Spring Security Thymeleaf đặc biệt, cho phép bạn đặt các biểu thức security trực tiếp vào các mẫu HTML Thymeleaf của bạn.

<div sec:authorize="isAuthenticated()">
This content is only shown to authenticated users.
</div>
<div sec:authorize="hasRole('ROLE_ADMIN')">
This content is only shown to administrators.
</div>
<div sec:authorize="hasRole('ROLE_USER')">
This content is only shown to users.
</div>

Để có cái nhìn tổng quan đầy đủ và chi tiết hơn về cách cả hai công nghệ hoạt động cùng nhau, hãy xem tài liệu chính thức .

Câu hỏi thường gặp

Phiên bản Spring Security mới nhất là gì?

Kể từ tháng 5 năm 2020, là phiên bản 5.3.2.

Lưu ý rằng nếu bạn đang sử dụng các dependency Spring Security được xác định bởi Spring Boot, bạn có thể đang sử dụng phiên bản Spring Security cũ hơn một chút, như 5.2.1.

Các phiên bản Spring Security cũ hơn có tương thích với phiên bản mới nhất không?

Spring Security gần đây đã trải qua một số thay đổi khá nặng. Do đó, bạn sẽ cần tìm các bài hướng dẫn chuyển đến các phiên bản được momg muốn của mình và làm việc thông qua chúng:

Tôi cần thêm những dependency nào để Spring Security hoạt động?

Dự án Plain Spring

Nếu bạn đang làm việc với một dự án Spring đơn giản ( không phải Spring Boot), bạn cần thêm hai dependency Maven/Gradle sau vào dự án của mình:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>

Bạn cũng sẽ cần cấu hình SecurityFilterChain trong cấu hình web.xml hoặc Java của mình. Xem cách thực hiện tại đây .

Dự án Spring Boot

Nếu bạn đang làm việc với một dự án Spring Boot, bạn cần thêm dependency Maven/Gradle sau vào dự án của mình:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Mọi thứ khác sẽ tự động được cấu hình cho bạn và bạn có thể bắt đầu viết ngay lập tức WebSecurityConfigurerAdapter của mình.

Làm cách nào để truy cập user hiện đã được authenticate trong Spring Security?

Như đã đề cập trong bài viết, Spring Security lưu trữ user hiện đã được authenticate (hay đúng hơn là SecurityContext) trong một variable luồng cục bộ bên trong SecurityContextHolder. Bạn có thể truy cập nó như này:

SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
String username = authentication.getName();
Object principal = authentication.getPrincipal();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();

Lưu ý rằng Spring Security theo mặc định sẽ đặt <em style="box-sizing:border-box">AnonymousAuthenticationToken</em> làm authentication trên SecurityContextHolder nếu như bạn chưa login. Điều này dẫn đến một số nhầm lẫn, vì mọi người thường mong đợi giá trị null tại đó.

AntMatchers: Các ví dụ phổ biến

Một ví dụ hiển thị các khả năng của antMatcher (và regexMatcher / mvcMatcher) hữu ích nhất:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
      .authorizeRequests()
      .antMatchers("/api/user/**", "/api/ticket/**", "/index").hasAuthority("ROLE_USER")
      .antMatchers(HttpMethod.POST, "/forms/**").hasAnyRole("ADMIN", "CALLCENTER")
      .antMatchers("/user/**").access("@webSecurity.check(authentication,request)");
}

Làm cách nào để sử dụng trang login tùy chỉnh với Spring Security?

@Override
protected void configure(HttpSecurity http) throws Exception {
http
      .authorizeRequests()
          .anyRequest().authenticated()
          .and()
      .formLogin()
          .loginPage("/login") // (1)
          .permitAll();
}
  1. URL cho trang login tùy chỉnh của bạn. Ngay sau khi bạn chỉ định, trang login được tạo tự động sẽ biến mất.

Làm cách nào để login với Spring Security?

UserDetails principal = userDetailsService.loadUserByUsername(username);
Authentication authentication = new UsernamePasswordAuthenticationToken(principal, principal.getPassword(), principal.getAuthorities());
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authentication);

Làm cách nào để vô hiệu hóa CSRF chỉ cho một số đường dẫn nhất định?

@Override
    protected void configure(HttpSecurity http) throws Exception {
      http
       .csrf().ignoringAntMatchers("/api/**");
    }

Vây

Nếu bạn đã đọc đến đây, bây giờ bạn đã hiểu khá rõ về sự phức tạp của hệ sinh thái Spring Security, ngay cả khi không có OAuth2. Tóm lại:

  1. Sẽ hữu ích nếu bạn có hiểu biết cơ bản về cách FilterChain của Spring Security hoạt động và các biện pháp bảo vệ mặc định khỏi bị khai thác thông tin của nó là gì (hãy quay lại: CSRF).

  2. Cần hiểu sự khác biệt giữa authentication và authorization. Và cả các @Beans nào bạn cần chỉ định cho quy trình authenticate cụ thể.

  3. Đảm bảo rằng bạn hiểu DSL của WebSecurityConfigurerAdapter của Spring Security cũng như method security dựa trên annotation.

  4. Cuối cùng nhưng không kém phần quan trọng, nó giúp kiểm tra lần nữa sự tích hợp với các framework và thư viện khác mà Spring Security có, như Spring MVC hoặc Thymeleaf.

Hôm nay đủ rồi, vì đó là một chuyến đi khá xa, phải không? Cảm ơn vì đã đọc!

Tham khảo Lộ trình Java Fullstack cho người mới bắt đầu

Khóa học - tại đây

Hỗ trợ - Ms Mẫn 0963023185 (zalo)