Pengenalan Ekspresi Keselamatan Musim Semi

1. Pengenalan

Dalam tutorial ini kita akan menumpukan pada Spring Security Expressions, dan tentu saja pada contoh praktikal dengan ungkapan-ungkapan ini.

Sebelum melihat pelaksanaan yang lebih kompleks (seperti ACL), penting untuk memahami ekspresi keselamatan - kerana ia boleh menjadi cukup fleksibel dan kuat jika digunakan dengan betul.

Artikel ini adalah lanjutan dari Spring Security Expressions - hasRole Contoh.

2. Pergantungan Maven

Untuk menggunakan Spring Security, anda perlu memasukkan bahagian berikut dalam fail pom.xml anda :

  org.springframework.security spring-security-web 5.2.3.RELEASE  

Versi terkini boleh didapati di sini.

Dan nota ringkas - kebergantungan ini hanya merangkumi Spring Security; jangan lupa untuk menambahkan konteks pring-core dan spring untuk aplikasi web penuh.

3. Konfigurasi

Pertama, mari kita lihat konfigurasi Java.

Kami akan memperluas WebSecurityConfigurerAdapter - supaya kami mempunyai pilihan untuk menghubungkan mana-mana titik pelanjutan yang ditawarkan kelas asas:

@Configuration @EnableAutoConfiguration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityJavaConfig extends WebSecurityConfigurerAdapter { ... }

Kami tentu saja dapat melakukan konfigurasi XML juga:

4. Ungkapan Keselamatan Web

Sekarang, mari mula melihat ungkapan keselamatan:

  • hasRole , hasAnyRole
  • hasAuthority , hasAnyAuthority
  • izinAll , denyAll
  • isAnonymous , isRememberMe , isAuthenticated , isFullyAuthenticated
  • prinsipal , pengesahan
  • mempunyaiPermission

Dan mari kita perhatikan setiap perkara secara terperinci.

4.1. hasRole, hasAnyRole

Ungkapan ini bertanggungjawab untuk menentukan kawalan akses atau kebenaran ke URL atau kaedah tertentu dalam aplikasi anda.

Mari lihat contohnya:

@Override protected void configure(final HttpSecurity http) throws Exception { ... .antMatchers("/auth/admin/*").hasRole("ADMIN") .antMatchers("/auth/*").hasAnyRole("ADMIN","USER") ... } 

Dalam contoh ini, kami menentukan akses ke semua pautan bermula dengan / auth / terhad kepada pengguna yang masuk dengan peranan USER atau ADMIN peranan . Lebih-lebih lagi, untuk mengakses pautan bermula dengan / auth / admin / kita perlu mempunyai peranan ADMIN dalam sistem.

Konfigurasi yang sama mungkin dicapai dalam fail XML, dengan menulis:

4.2. hasAuthority, hasAnyAuthority

Peranan dan pihak berkuasa serupa pada musim bunga.

Perbezaan utamanya ialah, peranan mempunyai semantik khas - bermula dengan Spring Security 4, awalan ' ROLE_ ' ditambahkan secara automatik (jika belum ada) dengan kaedah yang berkaitan dengan peranan apa pun.

Jadi hasAuthority ('ROLE_ADMIN') serupa dengan hasRole ('ADMIN') kerana awalan ' ROLE_ ' akan ditambahkan secara automatik.

Tetapi perkara yang baik tentang menggunakan pihak berkuasa adalah sama sekali kita tidak perlu menggunakan awalan ROLE_ .

Inilah contoh ringkas di mana kami menentukan pengguna dengan pihak berkuasa tertentu:

@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("user1").password(encoder().encode("user1Pass")) .authorities("USER") .and().withUser("admin").password(encoder().encode("adminPass")) .authorities("ADMIN"); } 

Sudah tentu kita boleh menggunakan ungkapan pihak berkuasa ini:

@Override protected void configure(final HttpSecurity http) throws Exception { ... .antMatchers("/auth/admin/*").hasAuthority("ADMIN") .antMatchers("/auth/*").hasAnyAuthority("ADMIN", "USER") ... }

Seperti yang dapat kita lihat - sama sekali kita tidak menyebut peranan. Selain itu, mulai Spring 5, kami memerlukan kacang PasswordEncoder :

@Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }

Akhirnya - kita tentu dapat mencapai fungsi yang sama menggunakan konfigurasi XML juga:

Dan:

4.3. izinAll, denyAll

Kedua-dua penjelasan itu juga cukup mudah. Kami mungkin membenarkan akses ke beberapa URL dalam perkhidmatan kami atau kami mungkin menolak akses.

Mari lihat contohnya:

... .antMatchers("/*").permitAll() ...

Dengan konfigurasi ini, kami akan memberi kebenaran kepada semua pengguna (tidak bernama dan log masuk) untuk mengakses halaman bermula dengan '/' (contohnya, laman utama kami).

Kami juga boleh menolak akses ke seluruh ruang URL kami:

... .antMatchers("/*").denyAll() ...

Dan sekali lagi, konfigurasi yang sama dapat dilakukan dengan konfigurasi XML juga:

4.4. isAnonymous, isRememberMe, isAuthenticated, isFullyAuthenticated

In this subsection we focus on expressions related to login status of the user. Let's start with user that didn't log in to our page. By specifying following in Java config, we enable all unauthorized users to access our main page:

... .antMatchers("/*").anonymous() ...

The same in XML config:

If we want to secure the website that everybody who uses it will be required to login, we need to use isAuthenticated() method:

... .antMatchers("/*").authenticated() ...

or XML version:

Moreover, we have two additional expressions, isRememberMe() and isFullyAuthenticated(). Through the use of cookies, Spring enables remember-me capabilities so there is no need to log into the system each time. You can read more about Remember Me here.

In order to give the access to users that were logged in only by remember me function, we may use this:

... .antMatchers("/*").rememberMe() ...

or XML version:

Finally, some parts of our services require the user to be authenticated again even if the user is already logged in. For example, user wants to change settings or payment information; it's of course good practice to ask for manual authentication in the more sensitive areas of the system.

In order to do that, we may specify isFullyAuthenticated(), which returns true if the user is not an anonymous or a remember-me user:

... .antMatchers("/*").fullyAuthenticated() ...

or the XML version:

4.5. principal, authentication

These expressions allow accessing the principal object representing the current authorized (or anonymous) user and the current Authentication object from the SecurityContext, respectively.

We can, for example, use principal to load a user's email, avatar, or any other data that is accessible in the logged in user.

And authentication provides information about the full Authentication object, along with its granted authorities.

Both are described in further detail in the following article: Retrieve User Information in Spring Security.

4.6. hasPermission APIs

This expression is documented and intended to bridge between the expression system and Spring Security’s ACL system, allowing us to specify authorization constraints on individual domain objects, based on abstract permissions.

Let's have a look at an example. We have a service that allows cooperative writing articles, with a main editor, deciding which article proposed by other authors should be published.

In order to allow usage of such a service, we may create following methods with access control methods:

@PreAuthorize("hasPermission(#articleId, 'isEditor')") public void acceptArticle(Article article) { … }

Only authorized user can call this method, and also user needs to have permission isEditor in the service.

We also need to remember to explicitly configure a PermissionEvaluator in our application context:

di mana customInterfaceImplementation akan menjadi kelas yang melaksanakan PermissionEvaluator.

Sudah tentu kita juga dapat melakukan ini dengan konfigurasi Java:

@Override protected MethodSecurityExpressionHandler expressionHandler() { DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler(); expressionHandler.setPermissionEvaluator(new CustomInterfaceImplementation()); return expressionHandler; }

5. Kesimpulan

Tutorial ini adalah pengenalan dan panduan menyeluruh untuk Spring Security Expressions.

Semua contoh yang dibincangkan di sini boleh didapati di projek GitHub.