在前面的章节中,我们沿用了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 {@Beanpublic 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:后面可以一直点 但是太多内容之后不美