您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~
前面的方法中,除了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进行测试的时候就能看到,现在的提示现在已经比刚才要友好了。
感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~
来源:https://www.cnblogs.com/xiangwang1111/p/16920329.html
本站部分图文来源于网络,如有侵权请联系删除。