SpringSecurity请求授权规则配置与注解详解
作者:流烟默
1、请求授权规则配置
这里主要是重写WebSecurityConfigurerAdapter 的configure方法。
protected void configure(HttpSecurity http) throws Exception { this.logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity)."); ((HttpSecurity)((HttpSecurity)((AuthorizedUrl)http. authorizeRequests() .anyRequest()) .authenticated() .and()) .formLogin() .and()) .httpBasic(); }
① 自定义登录
这里UsernamePasswordAuthenticationFilter 将起作用。
@Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() .loginPage("/login.html") //登录页面 .loginProcessingUrl("/user/login") // 默认处理登录的请求 .successForwardUrl("/success") //登录成功后跳转到哪个URL .defaultSuccessUrl("/index",true)// 登录成功后跳转路径 .failureForwardUrl("/fail") //登录失败后跳转到哪个URL .permitAll(); }
这里successForwardUrl与defaultSuccessUrl 都可以实现认证成功后跳转的效果,不过具体用法上有所区别。通常建议使用defaultSuccessUrl,至于具体区别后面另开章节学习。
还可以修改用户名和密码的key(默认是username 和password):
.usernameParameter("userName") //自定义获取用户登录名 .passwordParameter("password") //自定义获取用户登录密码
② 设置放行与需要认证的请求
http.authorizeRequests() .antMatchers("/static/**","/images/**","/css/**","/js/**")//可以直接放行 .permitAll()//匹配上述请求的直接放行 .anyRequest().authenticated();//其他请求都需要认证
③ 基于角色或权限进行访问控制
回顾上文我们自定义实现类设置用户角色权限如下:
这里用户角色、权限是指定的,那么我们是不是可以升级一下从数据库查询呢?如下图所示:
hasAuthority 方法
如果当前的主体具有指定的权限,则返回 true,否则返回false。
http.authorizeRequests() .antMatchers("/static/**","/images/**","/css/**","/js/**")//可以直接放行 .permitAll() .antMatchers("/findAll").hasAuthority("admin") // 用户访问findAll 必须有 admin 权限 .anyRequest().authenticated();//其他请求都需要认证
hasAnyAuthority方法
如果当前的主体有任何提供的角色(给定的作为一个逗号分隔的字符串列表)的话,返回true。
http.authorizeRequests() .antMatchers("/static/**","/images/**","/css/**","/js/**")//可以直接放行 .permitAll() .antMatchers("/findAll").hasAuthority("admin") // 用户访问findAll 必须有 admin 权限 .antMatchers("/find").hasAnyAuthority("admin","sale") // 用户访问 find ,拥有admin或者sale之一即可 .anyRequest().authenticated();//其他请求都需要认证
hasRole 方法
如果用户具备给定角色就允许访问,否则出现403。如果当前主体具有指定的角色,则返回true。
这里需要说明的是在SpringSecurity源码中对hasRole 进行了处理,为角色名自动添加上了ROLE_前缀。故我们配置的时候不加该前缀即可。
org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer#hasRole
http.authorizeRequests() .antMatchers("/static/**","/images/**","/css/**","/js/**")//可以直接放行 .permitAll() .antMatchers("/findAll").hasAuthority("admin") // 用户访问findAll 必须有 admin 权限 .antMatchers("/find").hasAnyAuthority("admin","sale") // 用户访问 find ,拥有admin或者sale之一即可 .antMatchers("/sale/**").hasRole("sale") // 需要用户具有sale角色 .anyRequest().authenticated();//其他请求都需要认证
hasAnyRole方法
表示用户具备任何一个条件都可以访问。
http.authorizeRequests() .antMatchers("/static/**","/images/**","/css/**","/js/**")//可以直接放行 .permitAll() .antMatchers("/findAll").hasAuthority("admin") // 用户访问findAll 必须有 admin 权限 .antMatchers("/find").hasAnyAuthority("admin","sale") // 用户访问 find ,拥有admin或者sale之一即可 .antMatchers("/sale/**").hasRole("sale") // 需要用户具有sale角色 .antMatchers("/product/**").hasAnyRole("admin","product") //用户具有admin或者product角色之一即可 .anyRequest().authenticated();//其他请求都需要认证
④ 自定义403访问拒绝页面
修改配置类
http.exceptionHandling().accessDeniedPage("/unauth.html");
这里需要说明的是你的静态资源文件路径下比如static下需要有unauth.html页面,当然这里也可以换成一个请求如/unauth,编写controller来处理该请求。
⑤ 自定义退出
修改配置类如下:
http.logout().logoutUrl("/logout") //退出登录请求 .logoutSuccessUrl("/index") //注销成功后跳转地址 .permitAll();
还可以指定在退出时删除某些cookie、注销会话:
.deleteCookies("remember-me","sign") .invalidateHttpSession(true)
2、SpringSecurity的注解
通过方法上的注解我们可以实现在后端服务上细粒度的权限校验。
主启动类上要添加@EnableGlobalMethodSecurity注解
@SpringBootApplication @MapperScan("com.jane.mapper") @EnableGlobalMethodSecurity(securedEnabled=true,prePostEnabled = true) public class Securitydemo1Application { public static void main(String[] args) { SpringApplication.run(Securitydemo1Application.class, args); } }
① @Secured
判断是否具有角色,另外需要注意的是这里匹配的字符串需要添加前缀“ROLE_“ 。使用该注解前要先开启注解支持:@EnableGlobalMethodSecurity(securedEnabled=true)
// 测试注解: @RequestMapping("testSecured") @ResponseBody @Secured({"ROLE_normal","ROLE_admin"}) public String helloUser() { return "hello,user"; }
② @PreAuthorize
先开启注解功能: @EnableGlobalMethodSecurity(prePostEnabled = true)。
@PreAuthorize注解适合进入方法前的权限验证,是一种常见的应用策略。
@RequestMapping("/preAuthorize") @ResponseBody //@PreAuthorize("hasRole('ROLE_admin')") @PreAuthorize("hasAnyAuthority('menu:system')") public String preAuthorize(){ System.out.println("preAuthorize"); return "preAuthorize"; }
可以看到这里权限表达式中可以使用hasRole、hasAnyRole、hasAuthority 以及hasAnyAuthority来灵活控制。
③ @PostAuthorize
先开启注解功能: @EnableGlobalMethodSecurity(prePostEnabled = true) 。@PostAuthorize 注解很少使用,在方法执行后再进行权限验证,适合验证带有返回值的权限。
@RequestMapping("/testPostAuthorize") @ResponseBody @PostAuthorize("hasAnyAuthority('menu:system')") public String preAuthorize(){ System.out.println("test--PostAuthorize"); return "PostAuthorize"; }
④ @PostFilter
@PostFilter :权限验证之后对数据进行过滤。表达式中的 filterObject 引用的是方法返回值List中的某一个元素。通常也很少使用。
如下留下用户名是admin1的数据:
@RequestMapping("getAll") @PreAuthorize("hasRole('ROLE_admin')") @PostFilter("filterObject.username == 'admin1'") @ResponseBody public List<UserInfo> getAllUser(){ ArrayList<UserInfo> list = new ArrayList<>(); list.add(new UserInfo(1l,"admin1","6666")); list.add(new UserInfo(2l,"admin2","888")); return list; }
⑤ @PreFilter
@PreFilter: 进入控制器之前对数据进行过滤。
@RequestMapping("getTestPreFilter") @PreAuthorize("hasRole('ROLE_admin')") @PreFilter(value = "filterObject.id%2==0") @ResponseBody public List<UserInfo> getTestPreFilter(@RequestBody List<UserInfo> list){ list.forEach(t-> { System.out.println(t.getId()+"\t"+t.getUsername()); }); return list; }
综上,这里我们常使用@Secured与@PreAuthorize两个注解在进入方法前进行角色、权限的控制。
进入方法前数据的过滤@PreFilter注解偶尔会看到,至于方法执行完后进行校验的两个注解@PostAuthorize与@PostFilter几乎不用。
到此这篇关于SpringSecurity请求授权规则配置与注解详解的文章就介绍到这了,更多相关SpringSecurity配置与注解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!