网站首页 > 文章精选 正文
上一篇文章中使用SpringSecurity实现基于MySQL的数据认证,我介绍了如何在SpringSecurity中使用数据库中的用户数据进行认证,这篇文章主要讲下怎么实现RBAC的权限认证,这就可以基本满足大多数情况下对权限认证的需求。
上篇文章其实已经将设置的用户权限取到了,这一步我们只需要自定义权限认证的逻辑,并交给SpringSecurity使用。
自定义权限认证的逻辑
@Component("authUserAccessConfig")
public class AuthUserAccessConfig {
private static final Logger logger = LoggerFactory.getLogger(AuthUserAccessConfig.class);
/**
* 判断当前访问的uri是否有权限
* @param request
* @param authentication
* @return
*/
public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
Object principal = authentication.getPrincipal();
String uri = request.getRequestURI();
// ajax请求都放行
// if (isAjax(request)) {
// return true;
// }
// 认证阶段放行
if (isAuth(uri)) {
return true;
}
// 认证成功的情况 - 判断权限相关
if (principal instanceof UserDetailsPojo) {
UserDetailsPojo authUser = (UserDetailsPojo) principal;
// 判断权限
String chkAuthUri = UriUtil.getChkAuthUri(uri);
// 获取登录用户的权限
Set<String> authMenuSet = authUser.getAuthMenuSet();
return authMenuSet.contains(chkAuthUri);
}
return false;
}
/**
* 判断请求是否是ajax
* @param request
* @return
*/
public boolean isAjax(HttpServletRequest request) {
return "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
}
public boolean isAuth(String uri) {
if (uri.equals("/login")) {
return true;
}
if (uri.equals("/error")) {
return true;
}
return false;
}
}
这里面会用到上篇文章定义的UserDetails的额外属性 Set<String> authMenuSet
// getter、setter就省略了
public class UserDetailsPojo implements UserDetails {
private static final long serialVersionUID = -987887L;
private String password;
private String username;
private Collection<? extends GrantedAuthority> authorities;
// 下面两个属性都是自定义添加的了 Set<String>是用来实现RBAC的权限认证
private Set<String> authMenuSet = new HashSet<>();
private long id;
}
通过authMenuSet保存的uri权限,进行判断当前用户是否有访问权限
配置自定义权限认证逻辑
@EnableWebSecurity
public class AuthConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers().frameOptions().disable();
http.authorizeRequests()
// 二者保其一 !!!!
.anyRequest().access("@authUserAccessConfig.hasPermission(request, authentication)")
// 所有请求都要是认证完成的
// .anyRequest().authenticated()
;
}
}
配置完成后所有的未被过滤的请求都会执行上面自定义的权限认证逻辑。
另外,我们也可以自定义当权限认证失败时该做什么动作。
自定义权限认证失败的动作
要实现自定义权限认证失败的逻辑,只需要实现AccessDeniedHandler接口并在SpringSecurity的配置类完成配置就可以了。
一般访问的请求会分为两种
- 异步请求Ajax
- 页面请求
所以当异步请求权限认证失败时,应该返回统一的接口响应格式的数据;当普通页面请求权限认证失败时,应该返回页面的403请求或其他4xx
1)创建实现AccessDeniedHandler接口的类
@Component
public class AuthAccessDeniedHandler implements AccessDeniedHandler {
private final Logger logger = LoggerFactory.getLogger(AuthAccessDeniedHandler.class);
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
logger.info("认证失败逻辑...");
if (!httpServletResponse.isCommitted()) {
if (isAjax(httpServletRequest)) {
logger.error(e.getMessage());
// 响应json格式数据
NetUtil.returnForbidden(httpServletResponse);
} else {
logger.error("跳转403页面了");
// 跳转到无权限页面
httpServletRequest.setAttribute(WebAttributes.ACCESS_DENIED_403, e);
httpServletResponse.setStatus(HttpStatus.FORBIDDEN.value());
RequestDispatcher dispatcher = httpServletRequest.getRequestDispatcher("/admin/auth/403");
dispatcher.forward(httpServletRequest, httpServletResponse);
}
}
}
/**
* 判断是否是ajax
* @param request
* @return
*/
public boolean isAjax(HttpServletRequest request) {
return "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
}
}
2)配置自定义权限认证失败逻辑
@EnableWebSecurity
public class AuthConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// 自定义验证权限失败处理器
http.exceptionHandling().accessDeniedHandler(new AuthAccessDeniedHandler());
}
}
完整SpringSecurity配置代码
@EnableWebSecurity
public class AuthConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsConfig userDetailsConfig;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsConfig).passwordEncoder(new BCryptPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers().frameOptions().disable();
http.authorizeRequests()
// 设置自定义的登录页可访问权限
.antMatchers("/sys/custom/login", "/login").permitAll()
.antMatchers("/druid/**").permitAll()
// 二者保其一 !!!!
.anyRequest().access("@authUserAccessConfig.hasPermission(request, authentication)")
// 所有请求都要是认证完成的
// .anyRequest().authenticated()
;
// 自定义验证权限失败处理器
http.exceptionHandling().accessDeniedHandler(new AuthAccessDeniedHandler());
// 自定义登录页
http.formLogin().loginPage("/sys/custom/login")
.usernameParameter("username")
.passwordParameter("password")
.failureUrl("/sys/custom/login?error=true")
.loginProcessingUrl("/login");
http.csrf().disable();
http.logout();
}
@Override
public void configure(WebSecurity web) throws Exception {
// 过滤所有前端资源
web.ignoring().antMatchers("/upfile/**", "/css/**", "/lib/**", "/js/**", "/font/**", "/images/**", "/favicon.ico");
}
}
小白升级打怪的过程中,最难的还是发现趁手的武器装备。
我是小白,我为小白代言。
猜你喜欢
- 2024-12-30 简单的使用SpringBoot整合SpringSecurity
- 2024-12-30 Spring Security 整合OAuth2 springsecurity整合oauth2+jwt+vue
- 2024-12-30 DeepSeek-Coder-V2震撼发布,尝鲜体验
- 2024-12-30 一个数组一行代码,Spring Security就接管了Swagger认证授权
- 2024-12-30 简单漂亮的(图床工具)开源图片上传工具——PicGo
- 2024-12-30 Spring Boot(十一):Spring Security 实现权限控制
- 2024-12-30 绝了!万字搞定 Spring Security,写得太好了
- 2024-12-30 SpringBoot集成Spring Security springboot集成springsecurity
- 2024-12-30 SpringSecurity密码加密方式简介 spring 密码加密
- 2024-12-30 Spring cloud Alibaba 从入门到放弃
- 最近发表
- 标签列表
-
- newcoder (56)
- 字符串的长度是指 (45)
- drawcontours()参数说明 (60)
- unsignedshortint (59)
- postman并发请求 (47)
- python列表删除 (50)
- 左程云什么水平 (56)
- 计算机网络的拓扑结构是指() (45)
- 稳压管的稳压区是工作在什么区 (45)
- 编程题 (64)
- postgresql默认端口 (66)
- 数据库的概念模型独立于 (48)
- 产生系统死锁的原因可能是由于 (51)
- 数据库中只存放视图的 (62)
- 在vi中退出不保存的命令是 (53)
- 哪个命令可以将普通用户转换成超级用户 (49)
- noscript标签的作用 (48)
- 联合利华网申 (49)
- swagger和postman (46)
- 结构化程序设计主要强调 (53)
- 172.1 (57)
- apipostwebsocket (47)
- 唯品会后台 (61)
- 简历助手 (56)
- offshow (61)