SpringSecurity03 基於內存驗證
1 需求
現有一個編寫好的系統,需要實現用戶登錄驗證即可,同時根據用戶的權限來限制用戶可以訪問的接口
2 編寫SpringSecurity配置類
繼承 WebSecurityConfigurerAdapter 類並重寫configure 方法
package cn.xiangxu.spring_security_system; //import cn.xiangxu.spring_security_system.service.MyUserService; import cn.xiangxu.spring_security_system.utils.MyPasswordEncoder;SpringSecurity配置類import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; /** * 權限服務類 */ @Configuration// 等同於XML中的beans @EnableWebSecurity // 開啟webSecurity功能 public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { // @Autowired // private MyUserService myUserService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 直接將用戶信息和權限寫死 auth.inMemoryAuthentication() .withUser("admin") .password("123456") .roles("ADMIN"); auth.inMemoryAuthentication() .withUser("wys") .password("123456") .roles("ADMIN"); auth.inMemoryAuthentication() .withUser("demo") .password("123456") .roles("USER"); // auth.userDetailsService(myUserService).passwordEncoder(new MyPasswordEncoder()); // 利用自定義的UserService進行管理 } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/").permitAll() // 主頁面請求攔截排除 .anyRequest().authenticated() // 除主頁面外的所有請求都會被攔截 .and() .logout().permitAll() // 註銷請求攔截排除 .and() .formLogin(); // 設置使用表單登錄的方式 http.csrf().disable(); // 關閉csrf驗證 } @Override public void configure(WebSecurity web) throws Exception { // 攔截排除設置 web.ignoring().antMatchers("/js/**", "/css/**", "/images/**"); } }
3 編寫一些接口用於測試
package cn.xiangxu.spring_security_system; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @RestController //@EnableGlobalMethodSecurity(prePostEnabled = true) // 開啟@PreAuthorize註解 public class SpringSecuritySystemApplication { public static void main(String[] args) { SpringApplication.run(SpringSecuritySystemApplication.class, args); } @GetMapping(value = "/") public String home() { return "Welcome to study springSecurity."; } @GetMapping(value = "/hello") public String hello() { return "hello boy"; } // @PreAuthorize("hasRole(‘ROLE_ADMIN‘)") // 設定權限校驗:只用ADMIN角色才能調用該接口 @GetMapping("/roleAuth") public String role() { return "admin role"; } }View Code
4 請求測試接口
利用硬編碼的用戶名和密碼進行登錄
5 設置權限校驗
5.1 在控制類上添加 @EnableGlobalMethodSecurity 註解
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.springframework.security.config.annotation.method.configuration; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.context.annotation.AdviceMode; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Documented @Import({GlobalMethodSecuritySelector.class}) @EnableGlobalAuthentication @Configuration public @interface EnableGlobalMethodSecurity { boolean prePostEnabled() default false; boolean securedEnabled() default false; boolean jsr250Enabled() default false; boolean proxyTargetClass() default false; AdviceMode mode() default AdviceMode.PROXY; int order() default 2147483647; }View Code
@EnableGlobalMethodSecurity(prePostEnabled = true)
代碼解釋:
整個項目啟用方法角色驗證註解,prePostEnabled = true 表示啟用@PreAuthorize 和 @PostAuthorize 兩個方法角色驗證註解(@PreFilter() 和 @PostFilter() 也會被啟用)
5.2 在需要進行角色驗證的接口上方添加 @PreAuthorize 註解
@PreAuthorize("hasRole(‘ROLE_ADMIN‘)")
代碼解釋:
有該註解的方法只有角色是ADMIN的用戶才可以訪問
package cn.xiangxu.spring_security_system; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @RestController @EnableGlobalMethodSecurity(prePostEnabled = true) // 開啟@PreAuthorize註解 public class SpringSecuritySystemApplication { public static void main(String[] args) { SpringApplication.run(SpringSecuritySystemApplication.class, args); } @GetMapping(value = "/") public String home() { return "Welcome to study springSecurity."; } @GetMapping(value = "/hello") public String hello() { return "hello boy"; } @PreAuthorize("hasRole(‘ROLE_ADMIN‘)") // 設定權限校驗:只用ADMIN角色才能調用該接口 @GetMapping("/roleAuth") public String role() { return "admin role"; } }View Code
6 權限校驗註解
6.1 @PreAuthorize
在執行方法之前進行權限校驗
6.1.1 角色驗證
例如:@PreAuthorize("hasRole(‘ROLE_ADMIN‘) or hasRole(‘ROLE_USER‘)") // ADMIN 和 USER 角色都有權限調用這個接口
package cn.xiangxu.spring_security_system; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.access.prepost.PostFilter; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreFilter; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @RestController @EnableGlobalMethodSecurity(prePostEnabled = true) // 開啟@PreAuthorize註解 public class SpringSecuritySystemApplication { public static void main(String[] args) { SpringApplication.run(SpringSecuritySystemApplication.class, args); } @GetMapping(value = "/") public String home() { return "Welcome to study springSecurity."; } @GetMapping(value = "/hello") public String hello() { return "hello boy"; } @PreAuthorize("hasRole(‘ROLE_ADMIN‘)") // 設定權限校驗:只用ADMIN角色才能調用該接口 @GetMapping("/roleAuth") public String role() { return "admin role"; } @PreAuthorize("hasRole(‘ROLE_ADMIN‘) or hasRole(‘ROLE_USER‘)") // ADMIN 和 USER 角色都有權限調用這個接口 @GetMapping("/test01") public String rest01() { return "test01"; } }View Code
6.1.2 參數驗證01
例如:@PreAuthorize("#id < 10")
代碼解釋: 方法必須有id參數,而且參數的值必須小於10
package cn.xiangxu.spring_security_system; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.access.prepost.PostFilter; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreFilter; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @RestController @EnableGlobalMethodSecurity(prePostEnabled = true) // 開啟@PreAuthorize註解 public class SpringSecuritySystemApplication { public static void main(String[] args) { SpringApplication.run(SpringSecuritySystemApplication.class, args); } @GetMapping(value = "/") public String home() { return "Welcome to study springSecurity."; } @GetMapping(value = "/hello") public String hello() { return "hello boy"; } @PreAuthorize("hasRole(‘ROLE_ADMIN‘)") // 設定權限校驗:只用ADMIN角色才能調用該接口 @GetMapping("/roleAuth") public String role() { return "admin role"; } @PreAuthorize("hasRole(‘ROLE_ADMIN‘) or hasRole(‘ROLE_USER‘)") // ADMIN 和 USER 角色都有權限調用這個接口 @GetMapping("/test01") public String rest01() { return "test01"; } @PreAuthorize("#id < 10") @GetMapping("/test02/{id}") public String test02(@PathVariable("id") Integer id) { return "test02 -> 獲取到的ID為:" + id; } }View Code
6.1.3 參數驗證03
例如:@PreAuthorize("principal.username.equals(#username)")
代碼解釋:方法必須有username參數,而且參數的值必須是登錄用戶的用戶名
package cn.xiangxu.spring_security_system; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.access.prepost.PostFilter; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreFilter; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @RestController @EnableGlobalMethodSecurity(prePostEnabled = true) // 開啟@PreAuthorize註解 public class SpringSecuritySystemApplication { public static void main(String[] args) { SpringApplication.run(SpringSecuritySystemApplication.class, args); } @GetMapping(value = "/") public String home() { return "Welcome to study springSecurity."; } @GetMapping(value = "/hello") public String hello() { return "hello boy"; } @PreAuthorize("hasRole(‘ROLE_ADMIN‘)") // 設定權限校驗:只用ADMIN角色才能調用該接口 @GetMapping("/roleAuth") public String role() { return "admin role"; } @PreAuthorize("hasRole(‘ROLE_ADMIN‘) or hasRole(‘ROLE_USER‘)") // ADMIN 和 USER 角色都有權限調用這個接口 @GetMapping("/test01") public String rest01() { return "test01"; } @PreAuthorize("#id < 10") @GetMapping("/test02/{id}") public String test02(@PathVariable("id") Integer id) { return "test02 -> 獲取到的ID為:" + id; } @PreAuthorize("principal.username.equals(#username)") @GetMapping("/test03") public String test03(@RequestParam("username") String username) { return "test03 -> 獲取到的username為:" + username; } }View Code
6.2 @PostAuthorize
在執行方法之後進行權限驗證
例如:@PostAuthorize("returnObject.equals(‘test04‘)")
代碼解釋:判斷方法的返回值是否等於 test04 , 如果是就通過驗證,如果不是就驗證失敗
技巧:returnObject代表方法的返回對象
package cn.xiangxu.spring_security_system; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.access.prepost.PostFilter; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreFilter; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @RestController @EnableGlobalMethodSecurity(prePostEnabled = true) // 開啟@PreAuthorize註解 public class SpringSecuritySystemApplication { public static void main(String[] args) { SpringApplication.run(SpringSecuritySystemApplication.class, args); } @GetMapping(value = "/") public String home() { return "Welcome to study springSecurity."; } @GetMapping(value = "/hello") public String hello() { return "hello boy"; } @PreAuthorize("hasRole(‘ROLE_ADMIN‘)") // 設定權限校驗:只用ADMIN角色才能調用該接口 @GetMapping("/roleAuth") public String role() { return "admin role"; } @PreAuthorize("hasRole(‘ROLE_ADMIN‘) or hasRole(‘ROLE_USER‘)") // ADMIN 和 USER 角色都有權限調用這個接口 @GetMapping("/test01") public String rest01() { return "test01"; } @PreAuthorize("#id < 10") @GetMapping("/test02/{id}") public String test02(@PathVariable("id") Integer id) { return "test02 -> 獲取到的ID為:" + id; } @PreAuthorize("principal.username.equals(#username)") @GetMapping("/test03") public String test03(@RequestParam("username") String username) { return "test03 -> 獲取到的username為:" + username; } @PostAuthorize("returnObject.equals(‘test04‘)") @GetMapping(value = "/test04") public String test04(@RequestParam("info") String info) { return info; } }View Code
6.3 @PreFilter
在方法執行前對列表型的參數進行一些驗證
例如:@PreFilter("filterObject%2==0")
·代碼解釋:列表型的參數中的每個元素必須能被2整除
技巧:filterObject 代表列表型的參數
6.4 @PostFilter("filterObject%4 == 0")
在方法執行後對返回的列表型對象進行一些驗證
例如:@PostFilter("filterObject%4 == 0")
代碼解釋:列表型的返回對象中的每個元素必須能被4整除
技巧:filterObject 代表列表型的返回對象
SpringSecurity03 基於內存驗證