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