本文作者:DurkBlue

谈一谈SpringSecurity如何实现多张用户表登陆验证逻辑推荐

DurkBlue 2023-11-16 264 抢沙发
谈一谈SpringSecurity如何实现多张用户表登陆验证逻辑摘要: 首先你要知道spring security的一些常识,登录验证由AuthenticationManager管理,但是它并不处理实际业务逻辑,它里面包含若干个Authenticati...

首先你要知道spring security的一些常识,登录验证由AuthenticationManager管理,但是它并不处理实际业务逻辑,它里面包含若干个Authenticationprovider,由provider来处理具体逻辑,只要我们实现多种Authenticationprovider,就能实现多种方式登录。

谈一谈SpringSecurity如何实现多张用户表登陆验证逻辑  第1张

首先是常规的代码,先来看两个不同的provider

/**
 * @Description : 管理员密码验证器
 * @Author : wzkris
 * @Version : V1.0.0
 * @Date : 2022/11/28 11:06
 */
@Component
@Slf4j
public class SysUserAuthenticationProvider implements AuthenticationProvider {
    @Resource(name = "sysUserDetailsServiceImpl")
    private UserDetailsService userDetailsService;
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        UserDetails userDetails = userDetailsService.loadUserByUsername(authentication.getName());
        return new UsernamePasswordAuthenticationToken(userDetails, authentication.getCredentials().toString(), userDetails.getAuthorities());
    }
    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(SysUserAuthenticationToken.class);
    }
}


/**
 * @Description : 用户密码验证器
 * @Author : wzkris
 * @Version : V1.0.0
 * @Date : 2022/11/28 12:47
 */
@Component
public class UserAuthenticationProvider implements AuthenticationProvider {
    @Resource(name = "userDetailsServiceImpl")
    private UserDetailsService userDetailsService;
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        UserDetails userDetails = userDetailsService.loadUserByUsername(authentication.getName());
        return new UsernamePasswordAuthenticationToken(userDetails, authentication.getCredentials().toString(), userDetails.getAuthorities());
    }
    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UserAuthenticationToken.class);
    }
}

provider的authentication方法处理具体的验证逻辑,那么supports方法是做什么用的呢?没错,在调用authentication方法之前,manager会先去调用supports方法,判断是否给当前provider处理,根据这一点,我们就能够无线扩展自己的逻辑。

后面的authentication方法会去调用UserDetailService,所以这里也需要两个实现类。

/**
 * @Description : 移动用户验证处理
 * @Author : wzkris
 * @Version : V1.0.0
 * @Date : 2022/11/28 12:48
 */
@Service
@Slf4j
public class UserDetailsServiceImpl implements UserDetailsService {
    @Resource
    private BusinessUserService businessUserService;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        BusinessUser user = businessUserService.queryByUsername(username);
        if (StringUtils.isNull(user)) {
            log.info("登录用户:{} 不存在.", username);
            throw new ServiceException("登录用户:" + username + " 不存在");
        } else if (user.getStatus().equals(Constants.FALSE)) {
            log.info("登录用户:{} 已被停用.", username);
            throw new ServiceException("对不起,您的账号:" + username + " 已停用");
        }
        return createLoginUser(user);
    }
    public UserDetails createLoginUser(BusinessUser user) {
        return new MobileUser(user);
    }
}


/**
 * @Description : 后台用户登录验证处理
 * @Author : wzkris
 * @Version : V1.0.0
 * @Date : 2022/11/29 12:38
 */
@Service
@Slf4j
public class SysUserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private ISysUserService userService;
    @Autowired
    private SysPasswordService passwordService;
    @Autowired
    private SysPermissionService permissionService;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
    {
        SysUser user = userService.selectUserByUserName(username);
        if (StringUtils.isNull(user))
        {
            log.info("登录用户:{} 不存在.", username);
            throw new ServiceException("登录用户:" + username + " 不存在");
        }
        else if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
        {
            log.info("登录用户:{} 已被删除.", username);
            throw new ServiceException("对不起,您的账号:" + username + " 已被删除");
        }
        else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
        {
            log.info("登录用户:{} 已被停用.", username);
            throw new ServiceException("对不起,您的账号:" + username + " 已停用");
        }
        passwordService.validate(user);
        return createLoginUser(user);
    }
    public UserDetails createLoginUser(SysUser user)
    {
        return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
    }
}


我这里做的就是后台用户才有权限,前台用户一视同仁

 然后拿出来另外两个类

/**
 * @Description : 后台用户
 * @Author : wzkris
 * @Version : V1.0.0
 * @Date : 2022/11/28 14:18
 */
public class SysUserAuthenticationToken extends UsernamePasswordAuthenticationToken {
    /**
     * 该方法只是用来选择对应的provider处理器
     */
    public SysUserAuthenticationToken(Object principal, Object credentials) {
        super(principal, credentials);
    }
}


/**
 * @Description : 前台用户
 * @Author : wzkris
 * @Version : V1.0.0
 * @Date : 2022/11/28 14:19
 */
public class UserAuthenticationToken extends UsernamePasswordAuthenticationToken {
    /**
     * 该方法只是用来选择对应的provider处理器
     */
    public UserAuthenticationToken(Object principal, Object credentials) {
        super(principal, credentials);
    }
}

可以看到,我只是实现了UsernamePasswordAuthenticationToken类,里面的逻辑没有做任何的改造,也就是说,这两个类只是拿来给manager去判断,然后调用相应的provider去处理逻辑。

至此,最初想解决的不同的登录方式对应不同的表的问题迎刃而解,我们还可以利用这一点,去扩展别的登录方式,例如对接微信登录、支付宝登录,或者是邮箱登录、手机验证码登录等等。


此篇文章由DurkBlue发布,撰文不易,转载请注明来处
文章投稿或转载声明

来源:DurkBlue版权归原作者所有,转载请保留出处。本站文章发布于 2023-11-16
温馨提示:文章内容系作者个人观点,不代表DurkBlue博客对其观点赞同或支持。

赞(1)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏

阅读
分享

发表评论取消回复

快捷回复:
AddoilApplauseBadlaughBombCoffeeFabulousFacepalmFecesFrownHeyhaInsidiousKeepFightingNoProbPigHeadShockedSinistersmileSlapSocialSweatTolaughWatermelonWittyWowYeahYellowdog

评论列表 (暂无评论,264人围观)参与讨论

还没有评论,来说两句吧...