您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~

前面的方法中,除了login()方法能成功,另外两个都失败,并不是因为代码问题,而是Spring Security默认是通过Web页面来实现页面逻辑跳转的。但在前后端分离的开发模式中,页面跳转的逻辑后端已经无法直接控制了,而是通过返回状态码由前端来执行跳转。因此,需要对应用进行改造。

首先自定义认证成功处理器,也就是实现AuthenticationSuccessHandler接口:

/**
* 自定义认证成功处理器
*
* @author 湘王
*/
@Component
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
System.out.println("登录成功"); // 前后端分离的调用方式
response.setStatus(HttpStatus.OK.value());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("OK");
}
}

接着来实现之前没有的认证失败处理器AuthenticationFailureHandler:

/**
* 自定义认证失败处理器
*
* @author 湘王
*/
@Component
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
System.out.println("user or password error"); // 前后端分离的调用方式
response.setStatus(HttpStatus.OK.value());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("user or password error");
}
}

再实现登出处理器LogoutSuccessHandler:

/**
* 自定义登出处理器
*
* @author 湘王
*/
@Component
public class CustomLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
System.out.println("登出成功"); // 前后端分离的调用方式
response.setStatus(HttpStatus.OK.value());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("OK");
}
}

然后修改之前的修改WebSecurityConfiguration,让过滤器中增加对这几个处理器的支持:

// 控制逻辑
@Override
protected void configure(HttpSecurity http) throws Exception {
// 执行UsernamePasswordAuthenticationFilter之前添加拦截过滤
http.addFilterBefore(new CustomInterceptorFilter(), UsernamePasswordAuthenticationFilter.class); http.authorizeRequests()
.anyRequest().authenticated()
// 设置自定义认证成功、失败及登出处理器
.and().formLogin().loginPage("/login")
.successHandler(successHandler).failureHandler(failureHandler).permitAll()
.and().logout().logoutUrl("/logout").deleteCookies("JSESSIONID")
.logoutSuccessHandler(logoutSuccessHandler).permitAll()
// 跨域访问
.and().cors()
.and().csrf().disable();
}

现在再次测试LoginController中的登录和登出操作,可以看到它们都能成功执行。目前权限已经做到了与Controller中的业务逻辑无关了。

但是仅仅做到登录、登出操作肯定是不行的,这连Demo都不如。所以接下里,来看看一个比较核心的问题:用户角色是否有效(不然建角色表干嘛)。

先在LoginController类中加入下面两个方法:

@GetMapping("/admin")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public String admin() {
return "admin有ROLE_ADMIN角色";
} @GetMapping("/manager")
@PreAuthorize("hasRole('ROLE_MANAGER')")
public String manager() {
return "manager有ROLE_MANAGER角色";
}

启动应用,运行postman时会发现:

1、用admin登录,访问localhost:8080/admin正常,但访问localhost:8080/manager就出现Forbidden错误;

2、用manager登录,访问localhost:8080/manager正常,而访问localhost:8080/admin也出现Forbidden错误。

这说明用户角色权限已经起作用了,但显示Forbidden的方式不够友好。所以再来增加一个自定义处理器,也就是实现AccessDeniedHandler接口,让访问拒绝友好一些:

/**
* 自定义访问被拒绝
*
* @author 湘王
*/
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException exception) throws IOException, ServletException {
System.out.println("permission denied"); // 前后端分离的调用方式
response.setStatus(HttpStatus.OK.value());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("permission denied");
}
}

然后同样地,要在WebSecurityConfiguration过滤器链中增加这个新增的过滤器:

// 控制逻辑
@Override
protected void configure(HttpSecurity http) throws Exception {
// 执行UsernamePasswordAuthenticationFilter之前添加拦截过滤
http.addFilterBefore(new CustomInterceptorFilter(), UsernamePasswordAuthenticationFilter.class); http.authorizeRequests()
.anyRequest().authenticated()
// 设置自定义认证成功、失败及登出处理器
.and().formLogin().loginPage("/login")
.successHandler(successHandler).failureHandler(failureHandler).permitAll()
.and().logout().logoutUrl("/logout").deleteCookies("JSESSIONID")
.logoutSuccessHandler(logoutSuccessHandler).permitAll()
// 配置无权访问的自定义处理器
.and().exceptionHandling().accessDeniedHandler(accessDeniedHandler)
.and().cors()
.and().csrf().disable();
}

再用postman进行测试的时候就能看到,现在的提示现在已经比刚才要友好了。


感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~

Spring Security(4)的更多相关文章

  1. Spring Security(08)——intercept-url配置

    http://elim.iteye.com/blog/2161056 Spring Security(08)--intercept-url配置 博客分类: spring Security Spring ...

  2. Spring Security(三)

    Spring Security(三) 个性化用户认证流程 自定义登录页面 在配置类中指定登录页面和接收登录的 url @Configuration public class BrowserSecuri ...

  3. Spring Security(二)

    Spring Security(二) 注:凡是源码部分,我已经把英文注释去掉了,有兴趣的同学可以在自己项目里进去看看.:-) 定义用户认证逻辑 用户登录成功后,用户的信息会被 Security 封装在 ...

  4. Spring Security(一)

    Spring Security(一) 基本原理 前言 Spring Security核心功能 认证(你是谁) 授权(你能干什么) 攻击防护(防止伪造身份) Srping Security基本原理 项目 ...

  5. 【权限管理系统】Spring security(三)---认证过程(原理解析,demo)

      在前面两节Spring security (一)架构框架-Component.Service.Filter分析和Spring Security(二)--WebSecurityConfigurer配 ...

  6. SpringBoot集成Spring Security(7)——认证流程

    文章目录 一.认证流程 二.多个请求共享认证信息 三.获取用户认证信息 在前面的六章中,介绍了 Spring Security 的基础使用,在继续深入向下的学习前,有必要理解清楚 Spring Sec ...

  7. SpringBoot集成Spring Security(6)——登录管理

    文章目录 一.自定义认证成功.失败处理 1.1 CustomAuthenticationSuccessHandler 1.2 CustomAuthenticationFailureHandler 1. ...

  8. SpringBoot集成Spring Security(5)——权限控制

    在第一篇中,我们说过,用户<–>角色<–>权限三层中,暂时不考虑权限,在这一篇,是时候把它完成了. 为了方便演示,这里的权限只是对角色赋予权限,也就是说同一个角色的用户,权限是 ...

  9. SpringBoot集成Spring Security(4)——自定义表单登录

    通过前面三篇文章,你应该大致了解了 Spring Security 的流程.你应该发现了,真正的 login 请求是由 Spring Security 帮我们处理的,那么我们如何实现自定义表单登录呢, ...

  10. SpringBoot集成Spring Security(2)——自动登录

    在上一章:SpringBoot集成Spring Security(1)——入门程序中,我们实现了入门程序,本篇为该程序加上自动登录的功能. 文章目录 一.修改login.html二.两种实现方式 2. ...

随机推荐

  1. 选择排序C语言版本

    算法思路,从头至尾扫描序列. 首先从第二个到最后,找出最小的一个元素,和第一个元素交换: 接着从第三个到最后,后面找出最小的一个元素,和第二个元素交换: 依次类推最终得到一个有序序列. void Se ...

  2. GreatSQL vs MySQL性能测试来了,速围观~

    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. GreatSQL是MySQL的国产分支版本,使用上与MySQL一致. 1.结论先行 无论ibp(innodb_buffer ...

  3. PLM产品生命周期管理,包含哪些阶段?

    PLM:Product Lifecycle Management=产品生命周期管理.产品的整个生命周期包括:投入期.成长期.成熟期.衰退期.结束期.PLM系统使企业可以把多年积累的所有产品相关数据放到 ...

  4. [Python]-tqdm模块-给for循环加上进度条

    import tqdm 使用tqdm模块,可以在漫长的for循环加上一个进度条,显示当前进度百分比. 将tqdm写在迭代器之外即可:tqdm(iterator) for i in tqdm(range ...

  5. 如何搭建安全的 CI/CD 管道?

    Eolink 前端负责人黎芷君进行了<工程化- CI / CD>的主题演讲,围绕 CI/CD 管道安全的实践,分享自己在搭建 CI/CD 管道过程中所总结的重要经验,与开发者深入讨论 &q ...

  6. 在Windows Server 2019上安装edge浏览器

    在Windows 2016和2019的正式版本中是不带Edge浏览器的.有些工具.网站也不支持IE浏览器了.对于偶尔需要在服务器上访问这些站点的管理员来说有些不方便.不过可以通过安装三方浏览器或者Ed ...

  7. 【COS生态建设】开发者有奖调研,等你来参与!

    为了更好的赋能开发者,为大家提供更好的开源应用,我们诚挚的邀请您抽出几分钟参与"有奖问卷",告诉我们您对"COS生态建设"的意见和建议.希望通过这份调查问卷,能 ...

  8. slf4j、log4j2及logback使用

    slf4j.log4j2及logback使用 1.问题来源 之前看过关于slf4j.log4j2及logback的介绍,slf4j是门面,log4j2及logback是具体实现,仅使用slf4j门面是 ...

  9. Java19虚拟线程都来了,我正在写的线程代码会被淘汰掉吗?

    Java19中引入了虚拟线程,虽然默认是关闭的,但是可以以Preview模式启用,这绝对是一个重大的更新,今天Java架构杂谈带大家开箱验货,看看这家伙实现了什么了不起的功能. 1 为什么需要虚拟线程 ...

  10. NOI2014 洛谷P2114 起床困难综合征(位运算)

    呃...这道题算是noi中比较简单的题吧...... 众所周知,位运算是个好东西,它就是对应的位进行运算,跟其他的位没有关系. 我们要选取一个m值使最后的攻击力最大,对于这个m,从高位开始枚举,判断该 ...