使用Spring-Security进行权限管理
1、认证与授权
- 【认证】你要登录论坛,输入用户名张三,密码 1234,密码正确,证明你张三确实是张三,这就是 authentication。
- 【授权】再一 check 用户张三是个版主,所以有权限加精删别人帖,这就是 authorization 。
2、导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lab-01-springsecurity-demo</artifactId>
<dependencies>
<!-- 实现对 Spring MVC 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 实现对 Spring Security 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
</project>
3、Application
创建 Application.java
类,配置 @SpringBootApplication
注解即可。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4、 创建SecurityConfig配置类
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
...
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.
// <X> 使用内存中的 InMemoryUserDetailsManager
inMemoryAuthentication()
// <Y> 不使用 PasswordEncoder 密码编码器
.passwordEncoder(NoOpPasswordEncoder.getInstance())
// <Z> 配置 admin 用户
.withUser("admin").password("admin").roles("ADMIN")
// <Z> 配置 normal 用户
.and().withUser("normal").password("normal").roles("NORMAL");
}
}
-
<X>
处,调用AuthenticationManagerBuilder#inMemoryAuthentication()
方法,使用内存级别的 InMemoryUserDetailsManager Bean 对象,提供认证的用户信息。-
Spring 内置了两种
UserDetailsManager
实现:
- InMemoryUserDetailsManager,和「2. 快速入门」是一样的。
- JdbcUserDetailsManager ,基于 JDBC的 JdbcUserDetailsManager 。
-
-
<Y>
处,调用AbstractDaoAuthenticationConfigurer#passwordEncoder(passwordEncoder)
方法,设置 PasswordEncoder 密码编码器。 -
<Z>
处,配置了「admin/admin」和「normal/normal」两个用户,分别对应 ADMIN 和 NORMAL 角色。
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// <X> 配置请求地址的权限
.authorizeRequests()
.antMatchers("/test/echo").permitAll() // 所有用户可访问
.antMatchers("/test/admin").hasRole("ADMIN") // 需要 ADMIN 角色
.antMatchers("/test/normal").access("hasRole('ROLE_NORMAL')") // 需要 NORMAL 角色。
// 任何请求,访问的用户都需要经过认证
.anyRequest().authenticated()
.and()
// <Y> 设置 Form 表单登录
.formLogin()
// .loginPage("/login") // 登录 URL 地址
.permitAll() // 所有用户可访问
.and()
// 配置退出相关
.logout()
// .logoutUrl("/logout") // 退出 URL 地址
.permitAll(); // 所有用户可访问
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
...
}
}
-
<X>
处,调用HttpSecurity#authorizeRequests()
方法,开始配置 URL 的权限控制。注意看艿艿配置的四个权限控制的配置。下面,是配置权限控制会使用到的方法:#(String... antPatterns)
方法,配置匹配的 URL 地址,基于 Ant 风格路径表达式 ,可传入多个。- 【常用】
#permitAll()
方法,所有用户可访问。 - 【常用】
#denyAll()
方法,所有用户不可访问。 - 【常用】
#authenticated()
方法,登录用户可访问。 #anonymous()
方法,无需登录,即匿名用户可访问。#rememberMe()
方法,通过 remember me 登录的用户可访问。#fullyAuthenticated()
方法,非 remember me 登录的用户可访问。#hasIpAddress(String ipaddressExpression)
方法,来自指定 IP 表达式的用户可访问。- 【常用】
#hasRole(String role)
方法, 拥有指定角色的用户可访问。 - 【常用】
#hasAnyRole(String... roles)
方法,拥有指定任一角色的用户可访问。 - 【常用】
#hasAuthority(String authority)
方法,拥有指定权限(authority
)的用户可访问。 - 【常用】
#hasAuthority(String... authorities)
方法,拥有指定任一权限(authority
)的用户可访问。 - 【最牛】
#access(String attribute)
方法,当 Spring EL 表达式的执行结果为true
时,可以访问。
-
<Y>
处,调用HttpSecurity#formLogin()
方法,设置 Form 表单登录。- 如果胖友想要自定义登录页面,可以通过
#loginPage(String loginPage)
方法,来进行设置。
- 如果胖友想要自定义登录页面,可以通过
-
<Z>
处,调用HttpSecurity#logout()
方法,配置退出相关。- 如果胖友想要自定义退出页面,可以通过
#logoutUrl(String logoutUrl)
方法,来进行设置。
- 如果胖友想要自定义退出页面,可以通过
5、TestController
创建 TestController 类,提供测试 API 接口。
// TestController.java
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/echo")
public String demo() {
return "示例返回";
}
@GetMapping("/home")
public String home() {
return "我是首页";
}
@GetMapping("/admin")
public String admin() {
return "我是管理员";
}
@GetMapping("/normal")
public String normal() {
return "我是普通用户";
}
}
- 对于
/test/echo
接口,直接访问,无需登录。 - 对于
/test/home
接口,无法直接访问,需要进行登录。 - 对于
/test/admin
接口,需要登录「admin/admin」用户,因为需要 ADMIN 角色。 - 对于
/test/normal
接口,需要登录「normal/normal」用户,因为需要 NORMAL 角色。