vue+spring-security前后端分离登录实现

本文探讨了vue.js与spring-security在前后端分离登录中的应用,比较了shiro与spring-security的区别,选择了基于session的安全策略。详细介绍了spring-security的权限控制实现,包括AuthenticationBuilder、UserDetailsService、DaoAuthenticationProvider等关键组件,并分享了axios的统一请求封装和spring-data在DAO层的使用。
摘要由CSDN通过智能技术生成

1.shiro和spring-security区别

首先Shiro较之Spring SecurityShiro在保持强大功能的同时,还在简单性和灵活性方面拥有巨大优势。Shiro是一个强大而灵活的开源安全框架,能够非常清晰的处理认证、授权、管理会话以及密码加密。

Spring Security除了不能脱离SpringShiro的功能它都有。Spring SecuritySpring结合较好,如果项目用的springmvc,使用起来很方便。

我们公司的登录认证主要使用了Shiro,实现了登录认证以及oauth2认证。提供了接口供不同个性化登录实现,如:

  1. IdentityBuilder:构建登录身份,控制登录流程
  2. UserService:查询用户真实信息
  3. CredentialsMatcher:校验登录身份和真实信息
  4. NamedAuthenticationListener:登录成功、失败的后处理

参照这套认证体系,我们采用Spring Security来重构以下。

2.jwt和session的选择

基于session和基于jwt的方式的主要区别就是用户的状态保存的位置,session是保存在服务端的,而jwt是保存在客户端的。jwt的优点就不说了,主要说说缺点

  1. 由于jwt的payload是使用base64编码的,并没有加密,因此jwt中不能存储敏感数据。而session的信息是存在服务端的,相对来说更安全。
  2. jwt太长。由于是无状态使用JWT,所有的数据都被放到JWT里,如果还要进行一些数据交换,那载荷会更大,经过编码之后导致jwt非常长,cookie的限制大小一般是4k,cookie很可能放不下,所以jwt一般放在local storage里面。并且用户在系统中的每一次http请求都会把jwt携带在Header里面,http请求的Header可能比Body还要大。而sessionId只是很短的一个字符串,因此使用jwt的http请求比使用session的开销大得多。
  3. 无状态是jwt的特点,但也导致了这个问题,jwt是一次性的。想修改里面的内容,就必须签发一个新的jwt。

为了安全性我们也是选择session来保存用户状态,而我们公司的系统经常要在服务端根据session进行权限控制,而jwt主要用在移动端的无状态场景。

3.spring-security权限控制实现

3.1 AuthenticationBuilder对标IdentityBuilder

Spring Security用一个类专门负责接手前端数据构建登录身份,这个类时UsernamePasswordAuthenticationFilter,但是这个类只能接受url请求中的参数,对于请求参数不在url中的则没法解析。所以我们需要个性化这个类让他能够Request PayLoad中的数据。

/**
 * {@link UsernamePasswordAuthenticationFilter}
 */
public class FrameUsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private final AuthenticationBuilder authenticationBuilder;

    public FrameUsernamePasswordAuthenticationFilter(AuthenticationBuilder authenticationBuilder) {
        super(new AntPathRequestMatcher("/api/login", "POST"));
        this.authenticationBuilder = authenticationBuilder;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) throws AuthenticationException {
        Authentication authRequest = authenticationBuilder.build(request, response);
        return this.getAuthenticationManager().authenticate(authRequest);
    }

}
复制代码

另外我们在封装一个AuthenticationBuilder接口用于个性化实现,并提供默认实现FrameAuthenticationBuilder

public class FrameAuthenticationBuilder implements AuthenticationBuilder {
    
    @Override
    public Authentication build(HttpServletRequest request, HttpServletResponse response) {
        LoginVO loginVO = JSON.parseObject(getRequestPayload(request), LoginVO.class);
        return new UsernamePasswordAuthenticationToken(
                loginVO.getUsername(), loginVO.getPassword());
    }

    public String getRequestPayload(HttpServletRequest request) {
        try {
            return IOUtils.toString(request.getReader());
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return "";
    }
}
复制代码

3.2 UserDetailsService对标UserService

Spring Security有个类专门负责通过username查找用户信息的接口,这个接口就是UserDetailsService

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //可以从数据库里根据username去除用户信息
    }
复制代码

3.3 DaoAuthenticationProvider对标CredentialsMatcher

AbstractUserDetailsAuthenticationProvider类提供了一个抽象方法additionalAuthenticationChecks用子类DaoAuthenticationProvider实现,UserDetails参数为AuthenticationBuilder构建的前端参数,UsernamePasswordAuthenticationTokenUserDetailsService通过前端传递的username去数据库中查询到的用户信息,对比两个对象的密码判断是否认证通过。值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值