视频教程地址: https://www.bilibili.com/video/BV1kT4y1F7Tc
代码地址: https://gitee.com/crazyliyang/video-teaching
1. 核心配置类 WebSecurityConfigurerAdapter
@Configuration@EnableGlobalMethodSecurity(prePostEnabled = true) // 注意public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests() // 配置请求地址的权限.antMatchers("/demo").permitAll() // 所有用户可访问,无需登录认证, @PermitAll 功能一样.antMatchers("/config/admin").hasRole("ADMIN") // 需要 ADMIN 角色.antMatchers("/config/normal").access("hasRole('ROLE_NORMAL')") // 需要 NORMAL 角色。.anyRequest().authenticated() // 任何请求,访问的用户都需要经过认证.and().formLogin() // 设置 Form 表单登陆// .loginPage("/login") // 登陆 URL 该地址这里可以自定义配置.permitAll().and().logout() // 配置退出相关// .logoutUrl("/logout") // 退出 URL 该地址这里可以自定义配置.permitAll();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication()// 使用内存中的 InMemoryUserDetailsManager.passwordEncoder(NoOpPasswordEncoder.getInstance())// 不使用 PasswordEncoder 密码编码器.withUser("admin").password("admin").roles("ADMIN") // 配置 admin 用户.and().withUser("user").password("user").roles("NORMAL");// 配置 normal 用户}}
如上的注释已经解释和常规的配置什么含义, 下边是总结:
当配置了上述的 WebSecurityConfigurerAdapter Java的配置类之后,我们的应用便具备了如下的功能:
除了“/”,”/home”(首页),”/login”(登录),”/logout”(注销)之外,其他路径都需要认证。
指定“/login”该路径为登录页面,当未认证的用户尝试访问任何受保护的资源时,都会跳转到“/login”。
默认指定“/logout”为注销页面
配置一个内存中的用户认证器,使用admin/admin作为用户名和密码,具有USER角色
防止CSRF攻击
还可以继续配置, 如下:
@Configurationpublic class CustomWebSecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/resources/**", "/signup", "/about").permitAll().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')").anyRequest().authenticated().and().formLogin().usernameParameter("username") // 指定登录用户名的参数名.passwordParameter("password") // 指定登录密码的参数名.failureForwardUrl("/login?error").loginPage("/login").permitAll().and().logout().logoutUrl("/logout").logoutSuccessUrl("/index").permitAll().and().httpBasic().disable();}}
其实在后边的自动装配流程原理分析, 和源码剖析会讲的更深入
如果是项目使用了使用JSP 还可以指定自己的登录页面, 登出页面, 如下所示:
SpringBoot 集成 JSP SpringBoot官方是不推荐在SpringBoot中使用jsp的,那么到底可以使用吗? 是可以的
不过需要导入tomcat插件启动项目,不能再用SpringBoot默认tomcat了。这里不拓展了, 因为现在大前端, 前后端分离已经是绝对的主流,这里就不讲这种老技术了.
http.authorizeRequests().antMatchers("/login.jsp", "/failer.jsp", "/css/**", "/img/**", "/plugins/**").permitAll() //以上指定的资源允许直接访问.anyRequest() .authenticated() // 其他资源设置拦截.and().formLogin().loginPage("/login.jsp") // 指定自定义的登录页面.loginProcessingUrl("/login").successForwardUrl("/index.jsp") // 成功后访问的地址.failureForwardUrl("/failer.jsp")// 失败后访问的地址.permitAll().and().logout().logoutUrl("/logout") //登出.invalidateHttpSession(true).logoutSuccessUrl("/login.jsp").permitAll().and().csrf().disable();
一个小小的案例说明; 来看下如何配置我们的 SpringSecurity 项目

核心配置类:
/**** 1.基于角色的权限访问控制RBAC(role-based access control)* 是以角色为中心进行的访问控制,判断当前请求用户 是否具有指定的角色, 是粗粒度的, 不建议采用;* </p>* 2.基于资源的权限访问控制RBAC(resource-based access control)* 是以资源为中心进行的访问控制,是以权限码(资源码) 来判断当前请求的用户是否具有指定的权限码(资源码) 细粒度, 建议采用;*/@Configuration@EnableGlobalMethodSecurity(prePostEnabled = true)public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {@Autowiredprivate UserService userService;@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests() // 配置请求地址的权限.antMatchers("/test01").permitAll() // 所有用户可访问,无需登录认证, @PermitAll 功能一样// 基于 权限码(资源码).antMatchers("/test02").hasAnyAuthority("sys.user.add","") // 含有这里指 权限码(资源码)数组中 任何一个即可.antMatchers("/test03").access("hasAnyAuthority('sys.user.add')").antMatchers("/test04").hasAuthority("sys.user.delete") // 必须含有指定的 权限码(资源码).antMatchers("/test05").access("hasAuthority('sys.user.delete')")// 基于角色.antMatchers("/test06").hasAnyRole("admin","manager") // 含有这里指 角色数组中 任何一个即可.antMatchers("/test07").access("hasAnyRole('ROLE_admin')").antMatchers("/test08").hasRole("admin") // 必须含有指定的 角色.antMatchers("/test09").access("hasRole('ROLE_admin')").anyRequest().authenticated() // 任何请求,访问的用户都需要经过认证.and().formLogin() // 设置 Form 表单登陆.permitAll().and().logout() // 配置退出相关.permitAll().and().csrf().disable();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth//inMemoryAuthentication()// 使用内存中的 InMemoryUserDetailsManager.userDetailsService(userService).passwordEncoder(NoOpPasswordEncoder.getInstance()); // 不使用 PasswordEncoder 密码编码器//.withUser("admin").password("admin").roles("ADMIN") // 配置 admin 用户//.and().withUser("user").password("user").roles("NORMAL");// 配置 normal 用户}}
UserService接口 和 UserServiceImpl
public interface UserService extends UserDetailsService {}@Servicepublic class UserServiceImpl implements UserService {// 模拟数据库private static Map<String, UserDetails> userDao = new HashMap();static {// 权限集合ArrayList<UserGrantedAuthority> list = new ArrayList<>();list.add(new UserGrantedAuthority("sys.user.delete"));list.add(new UserGrantedAuthority("sys.user.add"));list.add(new UserGrantedAuthority("sys.user.update"));list.add(new UserGrantedAuthority("sys.user.query"));list.add(new UserGrantedAuthority("sys.user.query"));list.add(new UserGrantedAuthority("ROLE_admin"));userDao.put("user1001", new UserEntity("user1001", "user1001",list));}public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {return userDao.get(username);}}
UserEntity 实体类
public class UserEntity implements UserDetails {private String username;private String password;private List<UserGrantedAuthority> userGrantedAuthorityList; // 权限集合public UserEntity() {}public UserEntity(String username, String password) {this.username = username;this.password = password;}public UserEntity(String username, String password, List<UserGrantedAuthority> userGrantedAuthorityList) {this.username = username;this.password = password;this.userGrantedAuthorityList = userGrantedAuthorityList;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return userGrantedAuthorityList;}// 设置权限public List<UserGrantedAuthority> getUserGrantedAuthorityList() {return userGrantedAuthorityList;}// 设置权限public void setUserGrantedAuthorityList(List<UserGrantedAuthority> userGrantedAuthorityList) {this.userGrantedAuthorityList = userGrantedAuthorityList;}@Overridepublic String getUsername() {return this.username;}@Overridepublic String getPassword() {return this.password;}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}}
UserGrantedAuthority 权限对象
public class UserGrantedAuthority implements GrantedAuthority {
private String grantedAuthorityStr; // 权限标识符 (资源标识符)
public UserGrantedAuthority() {}
public UserGrantedAuthority(String grantedAuthorityStr) {
this.grantedAuthorityStr = grantedAuthorityStr;
}
@Override
public String getAuthority() {
return grantedAuthorityStr;
}
public String getGrantedAuthorityStr() {
return grantedAuthorityStr;
}
public void setGrantedAuthorityStr(String grantedAuthorityStr) {
this.grantedAuthorityStr = grantedAuthorityStr;
}
}
TestControllerWithAnnotation 使用注解的测试类
@RestController
public class TestControllerWithAnnotation {
// 基于 权限码(资源码)
@PreAuthorize("hasAuthority('sys.user.add')")
@GetMapping("/test20")
public String test20() {
return "test20 success";
}
基于 权限码(资源码)
@PreAuthorize("hasAnyAuthority('sys.user.add','sys.user.delete')")
@GetMapping("/test21")
public String test21() {
return "test21 success";
}
// 基于角色
@PreAuthorize("hasRole('ROLE_admin')")
@GetMapping("/test22")
public String test22() {
return "test22 success";
}
// 基于角色
@PreAuthorize("hasAnyRole('ROLE_admin','ROLE_manager')")
@GetMapping("/test23")
public String test23() {
return "test23 success";
}
}
测试看结果 ! 本节完 !
视频教程地址: https://www.bilibili.com/video/BV1kT4y1F7Tc
代码地址: https://gitee.com/crazyliyang/video-teaching
