SpringSecurity系列——访问权限判断(权限,角色,IP),权限不足(403)处理day6-1(源于官网5.7.2版本)
前言
为了你对本文的内容不产生疑惑请先看下方说明
说明
关于本文的测试用户
本文测试用户为:
- 用户名:user1,密码:123,角色信息:
user,admin,权限信息:ROLE_user, ROLE_admin - 用户名:user2,密码:456,角色信息:
guest,权限信息:ROLE_guest
关于本文的其他类
AuthenticationEvents
package com.example.test1.config;
import org.springframework.context.event.EventListener;
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.authorization.event.AuthorizationDeniedEvent;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
@Component
public class AuthenticationEvents {
@EventListener
public void InteractiveSuccess(InteractiveAuthenticationSuccessEvent event){
System.out.println("interactive success");
System.out.println(event.getAuthentication().getAuthorities());
System.out.println(event.getAuthentication().getPrincipal());
// System.out.println(event.getAuthentication());
}
@EventListener
public void onFailure(AbstractAuthenticationFailureEvent failureEvent){
System.out.println("fail....");
System.out.println(failureEvent.getAuthentication());
System.out.println(failureEvent.getException());
}
DefineLogoutSuccessHandler
package com.example.test1.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
public class DefineLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
System.out.println("=============logout handler==============");
System.out.println(request.getMethod());
System.out.println(authentication.getPrincipal());
HashMap<String, Object> data = new HashMap<>();
data.put("status",200);
data.put("msg","退出登录成功");
data.put("userData",authentication.getPrincipal());
response.setContentType("application/json;charset=UTF-8");
String s = new ObjectMapper().writeValueAsString(data);
response.getWriter().println(s);
}
}
其余类的文章地址
基于权限的控制
只要在SpringSecurity中进行hasAuthority或hasAnyAuthority配置即可,具体写法如下
关键配置
hasAuthority单个权限控制
http.authorizeRequests(
auth ->
auth.antMatchers("/test").hasAuthority("ROLE_admin")
)
hasAnyAuthority多个权限控制中任意一个
http.authorizeRequests(
auth ->
.antMatchers("/test3").hasAnyAuthority("ROLE_admin","ROLE_user")
)
基于角色的控制
只要在SpringSecurity中进行hasRole或hasAnyRole配置即可,具体写法如下
关键配置
hasRole单个角色控制
http.authorizeRequests(
auth ->
auth.antMatchers("/test2").hasRole("admin")
)
hasAnyRole多个角色控制
http.authorizeRequests(
auth ->
auth.antMatchers("/test4").hasAnyRole("admin","user")
)
基于IP的控制
我们使用hasIpAddress方法进行配置
注意点
==本机地址localhost,127.0.0.1本机回环地址,本机地址这三个是不一样的!== 根据我测试下来情况如下
1. 设置hasIpAddress("localhost")
- 直接访问
127.0.0.1:8080/test5无需认证 - 直接访问
localhost:8080/test5无需认证 - 直接访问
192.168.28.159/test5需要认证
2. 设置hasIpAddress("127.0.0.1")
- 直接访问
127.0.0.1:8080/test5无需认证 - 直接访问
localhost:8080/test5无需认证 - 直接访问
192.168.28.159/test5需要认证
3. 设置hasIpAddress("192.168.28.159")
- 直接访问
127.0.0.1:8080/test5需要认证 - 直接访问
localhost:8080/test5需要认证 - 直接访问
192.168.28.159/test5无需认证
关键配置
http.authorizeRequests(
auth ->
auth.antMatchers("/test5").hasIpAddress("127.0.0.1")
)
测试结果说明
测试结果可想而知,user1是全部可以访问的,user2则是全部不能访问
当我看到如下错误的时候看到一个状态=403说明就是权限不够了
自定义403处理
当我们无权限时,SpringSecurity会给我们返回403的空白页面,实际上对用户是不友好的,用户不关心处理结果,只关心自己能否访问,所以自定义权限不足的时候的处理显得十分重要,在前后端分离的今天,其实我们只需要返回给前端json数据即可
实例代码
1.SpringSecurity中添加配置
关键配置
private final AuthenicationDeniedHandler deniedHandler;
@Autowired
public SpringSecurityConfig( AuthenicationDeniedHandler deniedHandler) {
this.deniedHandler = deniedHandler;
}
http.exceptionHandling().accessDeniedHandler(deniedHandler);
完整配置
package com.example.test1.config;
import com.example.test1.filter.LoginFilter;
import com.example.test1.service.impl.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationEventPublisher;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.SpringAuthorizationEventPublisher;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
@EnableWebSecurity
@Configuration
public class SpringSecurityConfig {
private final UserDetailsServiceImpl userDetailsService;
private final AuthenicationDeniedHandler deniedHandler;
@Autowired
public SpringSecurityConfig(UserDetailsServiceImpl userDetailsService, AuthenicationDeniedHandler deniedHandler) {
this.userDetailsService = userDetailsService;
this.deniedHandler = deniedHandler;
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
AuthenticationManager authenticationManager = configuration.getAuthenticationManager();
System.out.println(authenticationManager);
return configuration.getAuthenticationManager();
}
//身份验证事件,发布 AuthenticationEventPublisher
@Bean
public AuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
return new DefaultAuthenticationEventPublisher(applicationEventPublisher);
}
//认证事件
@Bean
public AuthorizationEventPublisher authorizationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
return new SpringAuthorizationEventPublisher(applicationEventPublisher);
}
// @Bean
// public LoginFilter loginFilter(){
// LoginFilter loginFilter = new LoginFilter();
// loginFilter.setUsernameParameter("username");
// loginFilter.setPasswordParameter("password");
// return loginFilter;
// }
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests(
auth -> auth.antMatchers("/test").hasAuthority("ROLE_admin")
.antMatchers("/test2").hasRole("admin")
.antMatchers("/test3").hasAnyAuthority("ROLE_admin", "ROLE_user")
.antMatchers("/test4").hasAnyRole("admin", "user")
.antMatchers("/test5").hasIpAddress("192.168.31.149")
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults())
// .and()
// .addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class)
.httpBasic(Customizer.withDefaults())
.logout(
logout ->
//自定义logout处理
logout.logoutSuccessHandler(new DefineLogoutSuccessHandler())
.invalidateHttpSession(true)
)
.userDetailsService(userDetailsService)
.exceptionHandling().accessDeniedHandler(deniedHandler);//异常处理
return http.build();
}
}
2.自定义处理
package com.example.test1.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
@Component
public class AuthenicationDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
System.out.println("========== access deny handler =================");
System.out.println(accessDeniedException.getMessage());
HashMap<String, Object> data = new HashMap<>();
data.put("status",403);
data.put("msg","用户权限不足!");
response.setContentType("application/json; charset=UTF-8");
String s = new ObjectMapper().writeValueAsString(data);
response.getWriter().println(s);
response.getWriter().flush();
response.getWriter().close();
}
}