web权限配置的三种方式
通过配置文件
spring.security.user.name=root
spring.security.user.password=root
通过配置类的方式
package cn.knightzz.security.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @author knightzz
* @date 2021/3/5 10:59
*/
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String encodePassword = passwordEncoder.encode("root");
auth.inMemoryAuthentication().withUser("root")
.password(encodePassword).roles("admin");
}
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
自定义实现类
-
步骤
第一步 : 创建配置 设置使用哪个 userDaoService实现类 第二步 : 编写实现类 返回user对象(包括用户密码以及操作权限)
-
代码
第一步 : 创建相关配置
package cn.knightzz.security.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; /** * @author knightzz * @date 2021/3/5 11:51 */ @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired UserDetailsService userDetailsService; @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Bean PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
第二步 : 编写 Service 类
package cn.knightzz.security.service; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; 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.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import java.util.List; /** * @author knightzz * @date 2021/3/5 11:57 */ @Service("userDetailsService") public class MyUserDetailsService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { // 模拟生成权限列表 List<GrantedAuthority> auths = AuthorityUtils. commaSeparatedStringToAuthorityList("role"); // 账号 , 密码, 权限集合 return new User("root" ,new BCryptPasswordEncoder().encode("root"),auths); } }
Controller认证
-
添加相关配置
package cn.knightzz.security.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; /** * @author knightzz * @date 2021/3/5 11:51 */ @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired UserDetailsService userDetailsService; @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Bean PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() // 自定义自己编写的登陆页面 .loginPage("/login.html") // 登陆页面设置 .loginProcessingUrl("/user/login") // 登陆访问路径 .defaultSuccessUrl("/test/index").permitAll() // 登陆成功以后的跳转路径 .and().authorizeRequests() .antMatchers("/", "/test/hello","/user/login").permitAll() // 设置哪些路径不需要认证可以直接访问 .anyRequest().authenticated() .and().csrf().disable(); // 关闭csrf防护 } }
-
编写登陆页面
登陆页面是在 static 目录下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登陆</title> </head> <body> <!-- 用户名和密码 必须设置成 username 和 password 否则 SpringSecurity无法识别 --> <form action="/user/login" method="post"> 用户名 : <input name="username" type="text"> <br /> 密码 : <input name="password" type="text"> <br/> <input type="submit" value="login"> </form> </body> </html>
-
测试
http://localhost:8111/test/index
基于权限或者角色进行访问控制
hasAuthority
-
第一步 在配置类中设置当前访问地址有哪些权限
// 当前登录用户 必须有admin 权限才可以访问 .antMatchers("/test/admin").hasAnyAuthority("admin")
-
第二步 在 UserDetailsService 设置相应权限
// 模拟生成权限列表 List<GrantedAuthority> auths = AuthorityUtils. commaSeparatedStringToAuthorityList("admin"); // 账号 , 密码, 权限集合 return new User("root" ,new BCryptPasswordEncoder().encode("root"),auths);
-
测试
http://localhost:8111/test/admin # 如果没有权限的话 结果 会报错 : Whitelabel Error Page There was an unexpected error (type=Forbidden, status=403).
hasAnyAuthority
// 作用
如果当前用户有提供的权限列表中的任何一个 返回 true
-
配置
// 当前用户必须要有权限列表中的任何一个都可以访问该路径 .antMatchers("/test/role").hasAnyAuthority("admin","superAdmin","role","user")
-
第二步 在 UserDetailsService 设置相应权限
// 模拟生成权限列表 用户角色使用 , 分割 List<GrantedAuthority> auths = AuthorityUtils. commaSeparatedStringToAuthorityList("admin,user,superAdmin"); // 账号 , 密码, 权限集合 return new User("root" ,new BCryptPasswordEncoder().encode("root"),auths);
-
测试
http://localhost:8111/test/role
hasRole
-
配置
// 需要有 ROLE_user 角色才能访问 .antMatchers("/test/role").hasRole("user")
-
第二步 在 UserDetailsService 设置相应权限
这里需要注意的是 角色列表 是 ROLE_ 开头的 否则会报错的
// 模拟生成权限列表 List<GrantedAuthority> auths = AuthorityUtils. commaSeparatedStringToAuthorityList("ROLE_user");
-
测试
http://localhost:8111/test/role
hasAnyRole
使用方式 与 hasAnyAuthority 类似
自定义403 访问页面
-
添加配置
// 配置没有权限访问跳转到自定义页面 http.exceptionHandling().accessDeniedPage("/403.html");
-
创建403页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>403</title> </head> <body> <h1>403 ! 没有访问权限</h1> </body> </html>
-
测试
http://localhost:8111/test/role
认证注解使用
@Secured
-
作用
用户必须 具有某个角色才能访问方法 1. 使用前必须开启注解功能: 在启动类(或者配置类)上添加开启注解 @EnableGlobalMethodSecurity(securedEnabled = true) public class SpringSecurityWebApplication {} 2. 需要注意的是 匹配字符串需要添加前缀 "ROLE" List<GrantedAuthority> auths = AuthorityUtils. commaSeparatedStringToAuthorityList("ROLE_admin,admin");
-
第二步 : 在 Controller 的方法中添加注解
@Secured({"ROLE_admin", "ROLE_manager"}) @GetMapping("update") public String update(){ return "hello update"; }
-
测试
http://localhost:8111/test/update
@PreAuthorize
-
作用
注解适合进入方法前的验证 1. 需要开启注解 @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) public class SpringSecurityWebApplication {} List<GrantedAuthority> auths = AuthorityUtils. commaSeparatedStringToAuthorityList("ROLE_admin,admin");
-
第二步 : 在 Controller 的方法中添加注解
@PreAuthorize("hasAnyAuthority('admin')") @GetMapping("auth") public String preAuthorize(){ return "hello PreAuthorize"; }
-
测试
http://localhost:8111/test/auth
@PostAuthorize
-
作用
1. 注解是在 方法执行后 才会验证权限的 2. 需要开启注解 @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) public class SpringSecurityWebApplication {} List<GrantedAuthority> auths = AuthorityUtils. commaSeparatedStringToAuthorityList("ROLE_admin,admin");
-
第二步 : 在 Controller 的方法中添加注解
@PostAuthorize("hasAnyAuthority('aaaa')") @GetMapping("post_auth") public String postAuthorize(){ System.out.println("postAuthorize"); return "hello postAuthorize"; }
-
测试
http://localhost:8111/test/post_auth // 测试结果 403 ! 没有访问权限 // 控制台会打印 hello postAuthorize
@PostFilter
-
作用
1. 权限验证之后对返回数据进行过滤 2. filterObject 对应返回值List的实体类 User 作用是 过滤掉 password 不等于 'admin01' 的数据 留下密码是 'admin01' 的数据 @GetMapping("user") @PreAuthorize("ROLE_admin") @PostFilter("filterObject.password == 'admin01'") public List<User> getAllUser(){
-
第二步 : 在 Controller 的方法中添加注解
@GetMapping("user") @PreAuthorize("ROLE_admin") @PostFilter("filterObject.password == 'admin01'") public List<User> getAllUser(){ List<User> users = new ArrayList<>(); users.add(new User("admin01", "12345")); users.add(new User("admin02", "admin02")); return users; }
-
使用 postman 测试
http://localhost:8111/test/user // 测试结果 [{"username":"admin02","password":"admin02"}]
@PreFilter
-
作用
1. 进入控制器之前对传入数据进行过滤 2. 过滤掉 username 不等于 admin01 的数据 filterObject就是 users 的 User 类 @GetMapping("filter") @PreAuthorize("hasAnyAuthority('ROLE_admin')") @PreFilter("filterObject.username == 'admin01'") public List<User> getTestPreFilter(List<User> users){}