在前面的章节中,我们沿用了Spring Security默认的安全机制:仅有一个用户,仅有一种角色。在实际开发中,这自然是无法满足需求的。本章将更加深入地对Spring Security迚行配置,且初步使用授权机制。
3.1 默认数据库模型的认证与授权
3.1.1、资源准备
首先,在controller包下新建三个控制器,如图所示。
其次,分别建立一些测试路由。
package com.boot.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/admin/api") public class AdminController { @GetMapping("/hello") public String hello(){ return "hello,admin"; } }
package com.boot.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/app/api") public class AppController { @GetMapping("/hello") public String hello(){ return "hello,app"; } }
package com.boot.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/user/api") public class UserController { @GetMapping("/hello") public String hello(){ return "hello,user"; } }
假设在/admin/api/下的内容是系统后台管理相关的API,在/app/api 下的内容是面向客户端公开访问的API,在/user/api/下的内容是用户操作自身数据相关的API;显然,/admin/api必须拥有管理员权限才能进行操作,而/user/api必须在用户登录后才能进行操作。
3.1.2、资源授权的配置
为了能正常访问前面的路由,我们需要进一步地配置Spring Security。
package com.boot.config; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.SecurityFilterChain; import org.springframework.util.StringUtils; import java.util.List; import static org.springframework.security.config.Customizer.withDefaults; //@EnableWebSecurity:开启SpringSecurity 之后会默认注册大量的过滤器servlet filter //过滤器链【责任链模式】SecurityFilterChain @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { //authorizeHttpRequests:针对http请求进行授权配置 //login登录页面需要匿名访问 //permitAll:具有所有权限 也就可以匿名可以访问 //anyRequest:任何请求 所有请求 //authenticated:认证【登录】 http.authorizeHttpRequests(authorizeHttpRequests-> authorizeHttpRequests //********************************角色**************************************** //.requestMatchers("/admin/api").hasRole("admin") //必须有admin角色才能访问到 //.requestMatchers("/user/api").hasAnyRole("admin","user") // /user/api:admin、user都是可以访问 //********************************权限**************************************** .requestMatchers("/admin/api").hasAuthority("admin:api") //必须有admin:api权限才能访问到 .requestMatchers("/user/api").hasAnyAuthority("admin:api","user:api") //有admin:api、user:api权限能访问到 //********************************匹配模式**************************************** .requestMatchers("/admin/api/?").hasAuthority("admin:api") //必须有admin:api权限才能访问到 .requestMatchers("/user/api/my/*").hasAuthority("admin:api") //必须有admin:api权限才能访问到 .requestMatchers("/admin/api/a/b/**").hasAuthority("admin:api") //必须有admin:api权限才能访问到 .requestMatchers("/app/api").permitAll() //匿名可以访问 .requestMatchers("/login").permitAll() .anyRequest().authenticated() ); //现在我们借助异常处理配置一个未授权页面:【实际上是不合理的 我们应该捕获异常信息 通过异常类型来判断是什么异常】 http.exceptionHandling(e->e.accessDeniedPage("/noAuth")); //http:后面可以一直点 但是太多内容之后不美