現有一個編寫好的系統,須要實現用戶登陸驗證便可,同時根據用戶的權限來限制用戶能夠訪問的接口css
繼承 WebSecurityConfigurerAdapter 類並重寫configure 方法java
package cn.xiangxu.spring_security_system; //import cn.xiangxu.spring_security_system.service.MyUserService; import cn.xiangxu.spring_security_system.utils.MyPasswordEncoder; 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/**"); } }
坑01:因爲從springboot2.0.3開始使用的springsecurity的版本是5.x,這個版本須要提供一個PasswordEncoder的實例,不然就會以下錯誤web
解坑01之方法01:只須要建立一個PasswordEncoder的Bean並被spring容器所管理便可算法
》建立一個實現了PasswordEncoder接口的實現類MyPasswordEncoder,在encode方法中編寫加密算法,在matches方法中編寫匹配算法spring
》在配置文件中配置MyPasswordEncoder對應的Bean便可(在一個標註了@Configuration註解的類中添加下面的邏輯便可)springboot
解坑01之方法02:在建立內存用戶的時候指定一個PasswordEncoder實例app
》建立一個實現了PasswordEncoder接口的實現類MyPasswordEncoder,在encode方法中編寫加密算法,在matches方法中編寫匹配算法ide
》建立內存用戶的時候直接指定PasswordEncoder便可post
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"; } }
利用硬編碼的用戶名和密碼進行登陸測試
// // 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; }
@EnableGlobalMethodSecurity(prePostEnabled = true)
代碼解釋:
整個項目啓用方法角色驗證註解,prePostEnabled = true 表示啓用@PreAuthorize 和 @PostAuthorize 兩個方法角色驗證註解(@PreFilter() 和 @PostFilter() 也會被啓用)
@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"; } }
6.1 @PreAuthorize
在執行方法以前進行權限校驗
例如:@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"; } }
例如:@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; } }
例如:@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; } }
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; } }
6.3 @PreFilter
在方法執行前對列表型的參數進行一些驗證
例如:@PreFilter("filterObject%2==0")
·代碼解釋:列表型的參數中的每一個元素必須能被2整除
技巧:filterObject 表明列表型的參數
6.4 @PostFilter("filterObject%4 == 0")
在方法執行後對返回的列表型對象進行一些驗證
例如:@PostFilter("filterObject%4 == 0")
代碼解釋:列表型的返回對象中的每一個元素必須能被4整除
技巧:filterObject 表明列表型的返回對象