Keselamatan Tahap Kaedah dengan Anotasi
Lindungi kaedah individu dalam lapisan perkhidmatan anda menggunakan anotasi Spring Security seperti `@PreAuthorize` dan `@PostAuthorize`.
Keselamatan Tahap Kaedah dengan Anotasi ialah pelajaran Keselamatan Spring dan Pengesahan JWT percuma di CoddyKit. Ini ialah pelajaran 2 daripada 4. Sebanyak 3 pelajaran dalam laluan pembelajaran ini boleh dibaca sepenuhnya secara percuma — selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan praktikal dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Keselamatan Spring dan Pengesahan JWT, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Keselamatan Spring dan Pengesahan JWT merangkumi sejumlah 4 pelajaran.
Pengenalan kepada Keselamatan Kaedah
Selamat datang! Dalam Keselamatan Spring, kita sering melindungi titik akhir web menggunakan HttpSecurity. Namun, bagaimana jika anda memerlukan kawalan yang lebih terperinci dalam logik aplikasi anda?
Keselamatan peringkat kaedah membolehkan anda melindungi kaedah individu dalam lapisan perkhidmatan, bagi memastikan hanya pengguna yang diberi kuasa boleh memanggilnya. Ini menambahkan satu lagi lapisan pertahanan yang berkuasa!
Mendayakan Keselamatan Kaedah
Untuk menggunakan keselamatan peringkat kaedah, anda perlu mendayakannya dalam konfigurasi Keselamatan Spring anda. Ini dilakukan dengan anotasi @EnableMethodSecurity.
Letakkannya pada kelas konfigurasi keselamatan utama anda, biasanya kelas yang melanjutkan WebSecurityConfigurerAdapter (walaupun dalam Spring Security 6, anda biasanya hanya menggunakan kelas @Configuration dengan FilterChainBean).
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
@Configuration
@EnableMethodSecurity // Enables @PreAuthorize, @PostAuthorize, etc.
public class SecurityConfig {
// Your security filter chain bean goes here
}@PreAuthorize: Sebelum Pelaksanaan
Anotasi @PreAuthorize menyemak kebenaran akses sebelum sesuatu kaedah dilaksanakan. Jika syarat tidak dipenuhi, kaedah tersebut tidak akan dijalankan dan AccessDeniedException akan dilemparkan.
Anotasi ini menggunakan Bahasa Ungkapan Spring (SpEL) untuk mentakrifkan peraturan kebenaran akses yang berkuasa. Kegunaan lazim termasuk menyemak peranan atau pihak berkuasa tertentu.
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
@Service
public class AdminService {
@PreAuthorize("hasRole('ADMIN')")
public String deleteSensitiveData() {
return "Sensitive data deleted!";
}
@PreAuthorize("hasAuthority('product:write')")
public String createProduct(String productName) {
return "Product '" + productName + "' created.";
}
}Menjalankan Contoh @PreAuthorize
Mari lihat @PreAuthorize berfungsi. Contoh yang boleh dijalankan ini mensimulasikan cara Keselamatan Spring memproses semakan hasRole('ADMIN') dengan menetapkan peranan pengguna secara manual dalam konteks keselamatan.
Cuba jalankannya untuk melihat cara akses diberikan atau ditolak berdasarkan peranan yang ditetapkan.
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import java.util.Collections;
import java.util.List;
public class Main {
// This method simulates a service method protected by @PreAuthorize("hasRole('ADMIN')")
public static String getAdminMessage() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
// In a real Spring app, AOP would handle this check before method entry.
// We simulate it here for demonstration.
if (auth != null && auth.getAuthorities().stream()
.anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"))) {
return "Welcome, Admin! Here's your secret message.";
} else {
return "Access Denied: ADMIN role required.";
}
}
public static void main(String[] args) {
// Scenario 1: User with ADMIN role
List<GrantedAuthority> adminAuthorities = Collections.singletonList(new SimpleGrantedAuthority("ROLE_ADMIN"));
Authentication adminAuth = new UsernamePasswordAuthenticationToken("adminUser", "pass", adminAuthorities);
SecurityContextHolder.getContext().setAuthentication(adminAuth);
System.out.println("Admin user attempt: " + getAdminMessage());
// Scenario 2: User with USER role
List<GrantedAuthority> userAuthorities = Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"));
Authentication userAuth = new UsernamePasswordAuthenticationToken("regularUser", "pass", userAuthorities);
SecurityContextHolder.getContext().setAuthentication(userAuth);
System.out.println("\nRegular user attempt: " + getAdminMessage());
SecurityContextHolder.clearContext(); // Clean up
}
}SpEL untuk Semakan Dinamik
@PreAuthorize boleh melakukan lebih daripada sekadar menyemak peranan! Anda boleh menggunakan SpEL untuk mengakses argumen kaedah, prinsipal yang disahkan, atau bean tersuai.
Contohnya, #userId merujuk kepada parameter kaedah bernama userId. authentication.principal.username mendapatkan nama pengguna semasa.
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
@Service
public class UserService {
// Only allow users to view their own profile
@PreAuthorize("#userId == authentication.principal.username")
public String viewUserProfile(String userId) {
return "Viewing profile for: " + userId;
}
// Allow ADMIN or the owner of the resource
@PreAuthorize("hasRole('ADMIN') or #resourceOwner == authentication.principal.username")
public String editResource(String resourceId, String resourceOwner) {
return "Editing resource '" + resourceId + "' by '" + resourceOwner + "'.";
}
}@PostAuthorize: Selepas Pelaksanaan
Kadang-kadang, anda perlu membuat keputusan kebenaran akses selepas kaedah selesai dilaksanakan dan anda mempunyai akses kepada nilai pulangannya. Di sinilah @PostAuthorize digunakan.
Anotasi ini berguna untuk memastikan pengguna yang disahkan dibenarkan untuk *melihat* data yang baru sahaja diperoleh atau diproses oleh kaedah tersebut. Anda boleh mengakses nilai pulangan menggunakan returnObject dalam SpEL.
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.stereotype.Service;
// A simple data class for demonstration
class UserProfile {
String username;
String email;
public UserProfile(String username, String email) {
this.username = username;
this.email = email;
}
public String getUsername() { return username; }
public String getEmail() { return email; }
}
@Service
public class ProfileService {
// Only allow access to profile if current user is the owner or an ADMIN
@PostAuthorize("returnObject.username == authentication.principal.username or hasRole('ADMIN')")
public UserProfile getUserProfile(String requestedUsername) {
// In a real app, this would fetch from a database
if ("john.doe".equals(requestedUsername)) {
return new UserProfile("john.doe", "john@example.com");
}
return new UserProfile("guest", "guest@example.com");
}
}Menjalankan Contoh @PostAuthorize
Contoh ini menunjukkan @PostAuthorize. Kami mensimulasikan pemulangan UserProfile, kemudian menyemak sama ada pengguna yang disahkan pada masa ini dibenarkan untuk melihatnya.
Perhatikan bahawa semakan berlaku *selepas* kaedah getUserProfile menghasilkan keputusannya.
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import java.util.Collections;
import java.util.List;
// Simple data class for demonstration
class UserProfile {
String username;
String email;
public UserProfile(String username, String email) {
this.username = username;
this.email = email;
}
public String getUsername() { return username; }
public String getEmail() { return email; }
@Override
public String toString() { return "Profile: " + username + " (" + email + ")"; }
}
public class Main {
// Simulates a service method with @PostAuthorize("returnObject.username == authentication.principal.username")
public static UserProfile getSecuredUserProfile(String requestedUsername) {
UserProfile profile = new UserProfile(requestedUsername, requestedUsername + "@example.com");
// Simulate @PostAuthorize check
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null && auth.isAuthenticated() &&
profile.getUsername().equals(auth.getName())) {
return profile; // Allowed to view own profile
} else if (auth != null && auth.isAuthenticated() &&
auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"))) {
return profile; // Admin can view any profile
} else {
// In a real app, this would be an AccessDeniedException
System.out.println("Access Denied to view profile for " + requestedUsername);
return null; // Or throw an exception
}
}
public static void main(String[] args) {
// Scenario 1: User viewing their own profile
List<GrantedAuthority> userAuthorities = Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"));
Authentication userAuth = new UsernamePasswordAuthenticationToken("alice", "pass", userAuthorities);
SecurityContextHolder.getContext().setAuthentication(userAuth);
System.out.println("Alice viewing her own profile: " + getSecuredUserProfile("alice"));
// Scenario 2: Alice trying to view Bob's profile
System.out.println("\nAlice viewing Bob's profile: " + getSecuredUserProfile("bob"));
// Scenario 3: Admin viewing Bob's profile
List<GrantedAuthority> adminAuthorities = Collections.singletonList(new SimpleGrantedAuthority("ROLE_ADMIN"));
Authentication adminAuth = new UsernamePasswordAuthenticationToken("admin", "pass", adminAuthorities);
SecurityContextHolder.getContext().setAuthentication(adminAuth);
System.out.println("\nAdmin viewing Bob's profile: " + getSecuredUserProfile("bob"));
SecurityContextHolder.clearContext();
}
}Menapis Koleksi: @PreFilter & @PostFilter
Untuk kaedah yang menerima atau memulangkan koleksi, Keselamatan Spring menyediakan @PreFilter dan @PostFilter.
@PreFilter: Menapis argumen koleksi *sebelum* kaedah dilaksanakan.@PostFilter: Menapis koleksi yang dipulangkan *selepas* kaedah dilaksanakan.
Ini berkuasa untuk situasi seperti memaparkan kepada pengguna hanya item dalam senarai yang dimilikinya, atau membenarkan kemas kini hanya pada elemen tertentu dalam satu kelompok.
import org.springframework.security.access.prepost.PreFilter;
import org.springframework.security.access.prepost.PostFilter;
import java.util.List;
class Item { String owner; String name; }
public class ItemService {
// Only allow items owned by the current user to be processed
@PreFilter("filterObject.owner == authentication.principal.username")
public void processItems(List<Item> items) {
// ... process only allowed items ...
}
// Only return items owned by the current user
@PostFilter("filterObject.owner == authentication.principal.username")
public List<Item> getAllItemsForUser() {
// ... fetch all items from DB ...
return List.of(new Item(), new Item()); // Returns filtered list
}
}Amalan Terbaik untuk Keselamatan Kaedah
Untuk menggunakan keselamatan peringkat kaedah dengan berkesan:
- Gunakan pada Lapisan Perkhidmatan: Asingkan logik perniagaan daripada pengawal. Lindungi kaedah perkhidmatan anda.
- Gabungkan dengan HttpSecurity: Gunakan keselamatan berasaskan URL untuk kawalan akses umum, dan keselamatan peringkat kaedah untuk keizinan terperinci. Kedua-duanya saling melengkapi.
- Pastikan SpEL Ringkas: SpEL yang kompleks boleh sukar dibaca dan dinyahpepijat. Pertimbangkan penilai keizinan tersuai untuk logik yang sangat rumit.
- Uji dengan Teliti: Sentiasa uji peraturan keselamatan anda untuk memastikan peraturan tersebut berfungsi seperti yang dijangkakan.
Semakan Pantas: Anotasi Kaedah
Anda sedang membina aplikasi dan perlu memastikan bahawa kaedah public void deleteUser(String userId) hanya boleh dipanggil oleh pengguna dengan peranan ADMIN, DAN hanya jika userId sepadan dengan ID pengguna yang sedang disahkan.
Ungkapan @PreAuthorize yang manakah akan menguatkuasakan perkara ini dengan betul?
Imbas Kembali & Langkah Seterusnya
Syabas! Anda telah mempelajari tentang keselamatan peringkat kaedah dalam Keselamatan Spring.
@EnableMethodSecuritymengaktifkan ciri ini.@PreAuthorizemenyemak keizinan *sebelum* kaedah dilaksanakan.@PostAuthorizemenyemak keizinan *selepas* kaedah dilaksanakan dengan memeriksa nilai pulangan.@PreFilterdan@PostFiltermembantu menapis argumen koleksi atau nilai pulangan.
Alat yang berkuasa ini membolehkan kawalan yang sangat tepat terhadap pihak yang boleh mengakses operasi dalaman aplikasi anda. Teruskan berlatih dan meneroka keupayaan SpEL!
Pelajari Java dengan tutor kecerdasan buatan — percuma
Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.
- Kursus
- 12
- Pelajaran
- 48
Soalan Lazim
Adakah pelajaran “Keselamatan Tahap Kaedah dengan Anotasi” percuma?
Ya — sebanyak 3 pelajaran dalam laluan pembelajaran Keselamatan Spring dan Pengesahan JWT, termasuk “Keselamatan Tahap Kaedah dengan Anotasi”, boleh dibaca sepenuhnya secara percuma di web ini. Selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan interaktif dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Kursus Keselamatan Spring dan Pengesahan JWT merangkumi sejumlah 4 pelajaran.
Apakah yang akan saya pelajari dalam “Keselamatan Tahap Kaedah dengan Anotasi”?
Lindungi kaedah individu dalam lapisan perkhidmatan anda menggunakan anotasi Spring Security seperti `@PreAuthorize` dan `@PostAuthorize`. Anda berlatih Keselamatan Spring dan Pengesahan JWT menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.
Adakah saya memerlukan pengalaman untuk memulakan Keselamatan Spring dan Pengesahan JWT?
Tiada pengalaman terdahulu diperlukan. Pembelajaran Keselamatan Spring dan Pengesahan JWT di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 2 daripada 4.
Berapa lamakah pelajaran “Keselamatan Tahap Kaedah dengan Anotasi” diambil?
Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.
Bolehkah saya menulis dan menjalankan kod dalam pelajaran Keselamatan Spring dan Pengesahan JWT ini?
Ya. Setiap pelajaran Keselamatan Spring dan Pengesahan JWT menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.
Semua pelajaran dalam kursus ini
- Kawalan Akses Berasaskan Peranan (RBAC)
- Keselamatan Tahap Kaedah dengan Anotasi
- Pendalaman Konfigurasi HttpSecurity
- Melindungi Titik Akhir dengan Peraturan Akses Tersuai