05 - spring security权限控制
spring security权限控制
文档
- 00 - spring security框架使用
- 01 - spring security自定义登录页面
- 02 - spring security基于配置文件及内存的账号密码
- 03 - spring security自定义登出页面
- 04 - spring security关闭csrf攻击防御
权限控制
完整的配置类WebSecurityConfig.java
package xin.yangshuai.springsecurity03.config;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.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;@Configuration
// @EnableWebSecurity
public class WebSecurityConfig {@Beanpublic UserDetailsService userDetailsService() {InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();// 此时配置文件中的用户名和密码将不可用manager.createUser(User.withDefaultPasswordEncoder().username("user").password("password").authorities("USER_LIST").build());return manager;}@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {// 开启授权保护http.authorizeRequests(new Customizer<ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry>() {@Overridepublic void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry expressionInterceptUrlRegistry) {// 具有USER_LIST权限的用户可以访问/user/listexpressionInterceptUrlRegistry.requestMatchers("/user/list").hasAuthority("USER_LIST");expressionInterceptUrlRegistry// 对所有请求开启授权保护.anyRequest()// 已经认证的请求会被自动授权.authenticated();}});// 自定义登录页面http.formLogin(new Customizer<FormLoginConfigurer<HttpSecurity>>() {@Overridepublic void customize(FormLoginConfigurer<HttpSecurity> httpSecurityFormLoginConfigurer) {// 自定义登录页,并且设置无需授权允许访问httpSecurityFormLoginConfigurer.loginPage("/login").permitAll();// 配置自定义表单的用户名参数,默认值:usernamehttpSecurityFormLoginConfigurer.usernameParameter("myusername");// 配置自定义表单的密码参数,默认值:passwordhttpSecurityFormLoginConfigurer.passwordParameter("mypassword");// 校验失败时跳转的地址,默认值:/login?errorhttpSecurityFormLoginConfigurer.failureUrl("/login?error");}});// 自定义登出页面http.logout(new Customizer<LogoutConfigurer<HttpSecurity>>() {@Overridepublic void customize(LogoutConfigurer<HttpSecurity> httpSecurityLogoutConfigurer) {// 自定义登出页httpSecurityLogoutConfigurer.logoutUrl("/logout");// 自定义登出成功后跳转的页面httpSecurityLogoutConfigurer.logoutSuccessUrl("/");}});return http.build();}
}
说明
- 以基于内存的用户为例,并且为用户设置权限,
.authorities("USER_LIST")
表示该用户具备USER_LIST
权限 - 对接口进行权限控制,
expressionInterceptUrlRegistry.requestMatchers("/user/list").hasAuthority("USER_LIST")
表示具有USER_LIST
权限的用户才可以访问该接口
配置/user/list
接口
package xin.yangshuai.springsecurity03.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import xin.yangshuai.common01.entity.BaseResult;import java.util.Arrays;
import java.util.List;@RestController
@RequestMapping("user")
public class SpringSecurityUserController {@GetMapping("list")public BaseResult<List<String>> list() {BaseResult<List<String>> result = new BaseResult<>();result.setCode("200");result.setData(Arrays.asList("zhangsan", "lisi", "wangwu"));return result;}
}
说明
- 由于上面在
WebSecurityConfig.java
配置文件中已经配置了接口的相关权限,所以在这里不需要配置 - 上面
WebSecurityConfig.java
中,如果将用户的权限去掉,则用户没有访问接口的权限,将会跳转到拒绝访问页面,这个页面可以自定义
自定义拒绝访问页面
调整配置类WebSecurityConfig.java
package xin.yangshuai.springsecurity03.config;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.configurers.ExceptionHandlingConfigurer;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;@Configuration
// @EnableWebSecurity
public class WebSecurityConfig {@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {// 开启授权保护// 自定义登录页面// 自定义登出页面// 自定义拒绝访问页面http.exceptionHandling(new Customizer<ExceptionHandlingConfigurer<HttpSecurity>>() {@Overridepublic void customize(ExceptionHandlingConfigurer<HttpSecurity> httpSecurityExceptionHandlingConfigurer) {httpSecurityExceptionHandlingConfigurer.accessDeniedPage("/accessDenied");}});return http.build();}
}
配置/accessDenied
接口
package xin.yangshuai.springsecurity03.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;@Controller
public class LoginController {// @GetMapping("login")// @GetMapping("logout")@GetMapping("accessDenied")public String accessDenied() {return "accessDenied";}
}
配置accessDenied.html
页面
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>拒绝访问页面</title>
</head>
<body>
<div>拒绝访问</div>
</body>
</html>
使用注解配置接口权限
可以在配置类中设置接口的权限,也可以在接口直接加注解的形式,为接口设置权限
配置类开启基于方法的授权,调整配置类WebSecurityConfig.java
,增加@EnableMethodSecurity
注解
package xin.yangshuai.springsecurity03.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;@Configuration
// @EnableWebSecurity
@EnableMethodSecurity //开启基于方法的授权
public class WebSecurityConfig {@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {// 开启授权保护http.authorizeRequests(new Customizer<ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry>() {@Overridepublic void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry expressionInterceptUrlRegistry) {// 具有USER_LIST权限的用户可以访问/user/list// expressionInterceptUrlRegistry.requestMatchers("/user/list").hasAuthority("USER_LIST");expressionInterceptUrlRegistry// 对所有请求开启授权保护.anyRequest()// 已经认证的请求会被自动授权.authenticated();}});// 自定义登录页面// 自定义登出页面// 自定义拒绝访问页面return http.build();}
}
说明:
- 使用注解的方式配置接口权限,就可以去掉过滤器中的相关配置了,实际上,过滤器中的配置与注解是同时起作用的。
调整/user/list
接口
package xin.yangshuai.springsecurity03.controller;import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import xin.yangshuai.common01.entity.BaseResult;import java.util.Arrays;
import java.util.List;@RestController
@RequestMapping("user")
public class SpringSecurityUserController {@GetMapping("list")@PreAuthorize("hasAuthority('USER_LIST')")public BaseResult<List<String>> list() {BaseResult<List<String>> result = new BaseResult<>();result.setCode("200");result.setData(Arrays.asList("zhangsan", "lisi", "wangwu"));return result;}
}
说明:
- 在接口上使用
@PreAuthorize("hasAuthority('USER_LIST')")
注解,表示访问该接口需要具有USER_LIST
权限 - 该注解可以有很多写法,比如:支持多个条件等