Saya ingin membuat kelas yang menambahkan metode kustom untuk digunakan dalam bahasa ekspresi keamanan musim semi untuk otorisasi berbasis metode melalui anotasi.
Misalnya, saya ingin membuat metode kustom seperti 'customMethodReturningBoolean' untuk digunakan seperti ini:
@PreAuthorize("customMethodReturningBoolean()")
public void myMethodToSecure() {
// whatever
}
Pertanyaan saya adalah ini. Jika memungkinkan, kelas apa yang harus saya subkelas untuk membuat metode kustom saya, bagaimana saya akan mengonfigurasinya di file konfigurasi spring xml dan datanglah seseorang memberi saya contoh metode kustom yang digunakan dengan cara ini?
java
spring
spring-security
Paul D. Eden
sumber
sumber
Jawaban:
Anda harus membuat subkelas dua kelas.
Pertama, setel penangan ekspresi metode baru
<global-method-security> <expression-handler ref="myMethodSecurityExpressionHandler"/> </global-method-security>
myMethodSecurityExpressionHandler
akan menjadi subkelasDefaultMethodSecurityExpressionHandler
yang menggantikannyacreateEvaluationContext()
, menyetel subkelas dariMethodSecurityExpressionRoot
padaMethodSecurityEvaluationContext
.Sebagai contoh:
@Override public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) { MethodSecurityEvaluationContext ctx = new MethodSecurityEvaluationContext(auth, mi, parameterNameDiscoverer); MethodSecurityExpressionRoot root = new MyMethodSecurityExpressionRoot(auth); root.setTrustResolver(trustResolver); root.setPermissionEvaluator(permissionEvaluator); root.setRoleHierarchy(roleHierarchy); ctx.setRootObject(root); return ctx; }
sumber
MethodSecurityExpressionRoot
menjadi paket pribadi ?Tak satu pun dari teknik yang disebutkan akan berhasil lagi. Tampaknya Spring telah berusaha keras untuk mencegah pengguna menimpa SecurityExpressionRoot.
EDIT 11/19/14 Setup Spring untuk menggunakan anotasi keamanan:
<beans ... xmlns:sec="http://www.springframework.org/schema/security" ... > ... <sec:global-method-security pre-post-annotations="enabled" />
Buat kacang seperti ini:
@Component("mySecurityService") public class MySecurityService { public boolean hasPermission(String key) { return true; } }
Kemudian lakukan sesuatu seperti ini di jsp Anda:
<sec:authorize access="@mySecurityService.hasPermission('special')"> <input type="button" value="Special Button" /> </sec:authorize>
Atau beri anotasi pada metode:
@PreAuthorize("@mySecurityService.hasPermission('special')") public void doSpecialStuff() { ... }
Selain itu, Anda dapat menggunakan Spring Expression Language di
@PreAuthorize
anotasi Anda untuk mengakses autentikasi saat ini serta argumen metode.Sebagai contoh:
@Component("mySecurityService") public class MySecurityService { public boolean hasPermission(Authentication authentication, String foo) { ... } }
Kemudian perbarui
@PreAuthorize
agar sesuai dengan tanda tangan metode baru:@PreAuthorize("@mySecurityService.hasPermission(authentication, #foo)") public void doSpecialStuff(String foo) { ... }
sumber
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
untuk mendapatkan token otentikasi saat ini.Terima kasih ericacm , tetapi tidak berfungsi karena beberapa alasan:
Perbedaannya adalah kita memanggil metode createEvaluationContext yang sudah ada, lalu menambahkan objek root kustom. Akhirnya saya baru saja mengembalikan tipe objek StandardEvaluationContext karena MethodSecurityEvaluationContext tidak akan menyelesaikan di compiler (keduanya dari antarmuka yang sama). Ini adalah kode yang sekarang saya miliki dalam produksi.
Jadikan MethodSecurityExpressionHandler menggunakan root kustom kami:
public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler { // parent constructor public CustomMethodSecurityExpressionHandler() { super(); } /** * Custom override to use {@link CustomSecurityExpressionRoot} * * Uses a {@link MethodSecurityEvaluationContext} as the <tt>EvaluationContext</tt> implementation and * configures it with a {@link MethodSecurityExpressionRoot} instance as the expression root object. */ @Override public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) { // due to private methods, call original method, then override it's root with ours StandardEvaluationContext ctx = (StandardEvaluationContext) super.createEvaluationContext(auth, mi); ctx.setRootObject( new CustomSecurityExpressionRoot(auth) ); return ctx; } }
Ini menggantikan root default dengan memperluas SecurityExpressionRoot . Di sini saya telah mengganti nama hasRole menjadi hasEntitlement:
public class CustomSecurityExpressionRoot extends SecurityExpressionRoot { // parent constructor public CustomSecurityExpressionRoot(Authentication a) { super(a); } /** * Pass through to hasRole preserving Entitlement method naming convention * @param expression * @return boolean */ public boolean hasEntitlement(String expression) { return hasRole(expression); } }
Terakhir, perbarui securityContext.xml (dan pastikan itu direferensikan dari applcationContext.xml Anda):
<!-- setup method level security using annotations --> <security:global-method-security jsr250-annotations="disabled" secured-annotations="disabled" pre-post-annotations="enabled"> <security:expression-handler ref="expressionHandler"/> </security:global-method-security> <!--<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">--> <bean id="expressionHandler" class="com.yourSite.security.CustomMethodSecurityExpressionHandler" />
Catatan: anotasi @Secured tidak akan menerima penggantian ini karena dijalankan melalui penangan validasi yang berbeda. Jadi, di xml di atas saya menonaktifkannya untuk mencegah kebingungan nanti.
sumber