Spring Security

本文介绍了如何将SpringSecurity从传统的前后端混合模式改造为前后端分离架构,通过替换默认的实现,使得所有交互均通过JSON返回,包括登录、登出、错误处理等,并详细展示了关键扩展点的重写过程。
摘要由CSDN通过智能技术生成

Spring Security 现状
我们在 SpringSecurity入门篇,快速搭建一个安全Web服务 已经搭建了一个基本的示例。其中的关键的流程如下:

当未登录用户访问项目时,会重定向到登录页(/login)。
登录成功后,会重定向到首页(也就是 / 路径)。
登录失败的话,会重定向到登录页。
登出后,会重定向到登录页。
登录后,鉴权失败(访问权限不足)时,会返回403响应。
可以看出来,这妥妥的很不’前后端分离’,后端还会返回html页面并且各种重定向。好在 Spring Security 扩展性足够好,支持替换默认的实现,下文便来掰扯掰扯。

Spring Security 前后端分离改造
前后端分离的要点就是,后端的响应统一通过 JSON 格式返回,而不是html或者重定向。 基于这个出发点,我们将替换原有的实现类。

定义统一的响应格式
改造的第一点,则是定义一个统一的响应格式:

统一的响应格式
@Data
@Accessors(chain = true)
public class RestResult<T> {

    private int code;
    private T data;
    private String msg;

    private RestResult() {
    }

    public static RestResult success() {
        return new RestResult().setCode(200);
    }

    public static RestResult success(Object data) {
        return success().setData(data);
    }

    public static RestResult error() {
        return new RestResult().setCode(500);
    }

    public static RestResult error(String errMsg) {
        return error().setMsg(errMsg);
    }

    public static RestResult error(int code, String errMsg) {
        return new RestResult().setCode(code).setMsg(errMsg);
    }

    public static RestResult error(Exception ex) {
        return error(ex.getMessage());
    }

    public String toJsonString() {
        return JsonUtils.toJsonString(this);
    }

}


重写默认实现,并替换(重点)
涉及到的扩展点:

登录成功处理:AuthenticationSuccessHandler
登录失败处理:AuthenticationFailureHandler
登出成功处理:LogoutSuccessHandler
未登录处理:AuthenticationEntryPoint
鉴权失败处理:AccessDeniedHandler
注意看代码中的注释,改造点对应上文中提到的原有流程的序号!

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()

                // 表单登录
                .formLogin()
                // 登录成功处理(对应流程2)
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        response.setContentType("application/json;charset=utf-8");
                        response.getWriter().write(RestResult.success().toJsonString());
                    }
                })
                // 登录失败处理(对应流程3)
                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
                        response.setContentType("application/json;charset=utf-8");
                        response.getWriter().write(RestResult.error(exception).toJsonString());
                    }
                })
                .and()

                //登出
                .logout()
                //登出成功处理(对应流程4)
                .logoutSuccessHandler(new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        response.setContentType("application/json;charset=utf-8");
                        response.getWriter().write(RestResult.success().toJsonString());
                    }
                })
                .and()

                //异常处理
                .exceptionHandling()
                //未登录处理(对应流程1)
                .authenticationEntryPoint(new AuthenticationEntryPoint() {
                    @Override
                    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
                        response.setContentType("application/json;charset=utf-8");
                        response.getWriter().write(RestResult.error(HttpServletResponse.SC_UNAUTHORIZED, "未登录").toJsonString());
                    }
                })
                //没有权限处理(对应流程5)
                .accessDeniedHandler(new AccessDeniedHandler() {
                    @Override
                    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
                        response.setContentType("application/json;charset=utf-8");
                        response.getWriter().write(RestResult.error(HttpServletResponse.SC_FORBIDDEN, "没有权限").toJsonString());
                    }
                })
                .and()
                .csrf().disable();
    }

}


测试
直接测试原有流程,看看效果如何:

未登录时访问接口

很好,达到我们目的了,改造后,它并不是重定向到登录页,而是通过json响应回来401。ok

登录失败

同样的以json格式响应。nice

登录成功

输入正确的帐号密码,登录成功,json响应200。perfect

登出

over over

另外
项目还是利用 cookie-session 机制维持会话状态。
统一响应格式利用code判断请求是否成功。(还有一种方式是利用 HTTP状态码)

以下是关于Spring Security的一些知识点:

1. 身份验证(Authentication):Spring Security提供了多种身份验证方式,包括基于用户名和密码的身份验证、LDAP身份验证、OAuth身份验证等。

2. 授权(Authorization):Spring Security支持基于角色和权限的授权机制。通过配置角色和权限,可以限制用户对资源的访问。

3. 访问控制(Access Control):Spring Security提供了多种访问控制的方式,包括基于URL的访问控制、基于方法级别的访问控制以及基于表达式的访问控制。

4. Remember Me功能:Spring Security支持"Remember Me"功能,允许用户在多个会话之间保持登录状态。

5. Session管理:Spring Security处理会话管理,包括会话固定保护、无效会话管理和并发会话控制。

6. CSRF保护:Spring Security内置了对跨站请求伪造(CSRF)进行保护的机制,防止利用网站与用户之间的信任来进行攻击。

7. 集成其他框架:Spring Security与其他Spring项目(如Spring MVC和Spring Boot)无缝集成,方便在应用程序中添加安全功能。

8. 定制化:Spring Security提供丰富的定制化选项,可以根据具体需求进行配置和扩展。

总之,Spring Security是一个功能强大且高度可定制的安全框架,适用于Java应用程序。它简化了在应用程序中实施强大安全措施的过程,为保护敏感数据和防止未经授权的访问提供了坚实的基础。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值