首页 > 其他分享 >Spring Security实现多用户系统登录

Spring Security实现多用户系统登录

时间:2023-06-29 18:00:48浏览次数:38  
标签:userDetailService String 多用户 Spring private range Security public CustomUserDeta

由于管理层的突发奇想,硬要把我负责的系统塞到其他的项目中去,而系统之间的用户系统又不同,如果要合并到一起,那改动将是非常大,于是就产生这个多用户系统登录的问题。

因为userDetailService是通过用户名来查找用户信息的,所以具体实现得通过多个userDetailService提供用户信息,每个用户系统定义一个userDetailService,在认证的时候根据策略选择相应的userDetailService。这里我们定义一个CustomUserDetailService将userDetailService包装一下,提供一个supports方法作为选择策略。

 

public interface CustomUserDetailService extends UserDetailsService {
 
    Boolean supports(String range);// 判断依据
}

 两个系统的表定为user表与member表,接下来我们实现对应的userDetailService,并指定serveice的名称

@Slf4j
@Service("adminUserDetailService")
public class AdminUserDetailService implements CustomUserDetailService {
 
    private final String RANGE = "a";
 
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        // ......
    }
 
    @Override
    public Boolean supports(String range){
        return RANGE.equals(range);
    }
 }
@Service("memberUserDetailService")
@Slf4j
public class MemberUserDetailService implements CustomUserDetailService {
    private final String RANGE = "m";
 
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        // ......
    }
 
    @Override
    public Boolean supports(String range){
        return RANGE.equals(range);
    }
}

接下来我们需要重写AuthenticationProvider类,让它能提供多个userDetailService,并根据策略选择相应的userDetailService进行处理。这里我们复制org.springframework.security.authentication.dao.DaoAuthenticationProvider这个实现类作为我们的实现类,然后定义一个getUserDetailsServices()方法接收多个userDetailService,然后重写retrieveUser()方法来选择应使用的userDetailService。

public class AuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
    ··············
    private List<CustomUserDetailService> userDetailsServices;
 
    protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        this.prepareTimingAttackProtection();
        try {
            String detail = (String) authentication.getDetails();
            UserDetails loadedUser = null;
            for (CustomUserDetailService userDetailsService : this.getUserDetailsServices()){

                if(userDetailsService.supports(detail)){
                    loadedUser = userDetailsService.loadUserByUsername(username);
                    break;
                }
            }

            if (loadedUser == null) {
                throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation");
            } else {
                return loadedUser;
            }
        } catch (UsernameNotFoundException var4) {
            this.mitigateAgainstTimingAttack(authentication);
            throw var4;
        } catch (InternalAuthenticationServiceException var5) {
            throw var5;
        } catch (Exception var6) {
            throw new InternalAuthenticationServiceException(var6.getMessage(), var6);
        }
    }

    public List<CustomUserDetailService> getUserDetailsServices() {
        return userDetailsServices;
    }

    public void setUserDetailsServices(List<CustomUserDetailService> userDetailsServices) {
        this.userDetailsServices = userDetailsServices;
    }
··········
}

接下来配置WebSecurityConfigurerAdapter

    @Qualifier("adminUserDetailService")
    @Autowired
    private CustomUserDetailService adminUserDetailService;
 
    @Qualifier("memberUserDetailService")
    @Autowired
    private CustomUserDetailService memberUserDetailService;
 
    @Override
    protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        AuthenticationProvider authenticationProvider = new AuthenticationProvider();
        authenticationProvider.setPasswordEncoder(passwordEncoder());
        List<CustomUserDetailService> userDetailServices = new ArrayList<>();
        userDetailServices.add(memberUserDetailService);
        userDetailServices.add(adminUserDetailService);
        authenticationProvider.setUserDetailsServices(userDetailServices);
        authenticationManagerBuilder.authenticationProvider(authenticationProvider);
    }

 最后就是处理登录了,前面我们重写AuthenticationProvider中的retrieveUser()方法时是通过UsernamePasswordAuthenticationToken中的details来进行判断使用哪个userDetailService的,所以在创建UsernamePasswordAuthenticationToken后需要把"range"设置到details中。details是父类中的一个Object类型的成员变量。在登录服务中,创建authenticationToken后,我们设置好details,这里我是在用户实体中新增了一个flag参数,不同的系统传入不同值,当然,如果各个系统调用的登录接口不同,我们也可以不用新增参数直接在这里写死。

 

public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer {
    private final Collection<GrantedAuthority> authorities;
    private Object details;
    ......
}
 public String login(User user) {
        String username = user.getUsername();
        String password = user.getPassword();
        // 用户验证
        Authentication authentication = null;
        try
        {
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
            authenticationToken.setDetails(user.getFlag());
            AuthenticationContextHolder.setContext(authenticationToken);
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager.authenticate(authenticationToken);
        }
        catch (Exception e)
        {
        }

这样就完成了多用户系统登录的实现。

引用文章:http://dexian.net.cn/archives/springsecurity-duo-ge-yong-hu-biao

标签:userDetailService,String,多用户,Spring,private,range,Security,public,CustomUserDeta
From: https://www.cnblogs.com/qq545505061/p/17511591.html

相关文章

  • spring某些类只有在prod环境生效
    spring某些类只有在prod环境生效并加载bean@Profile("prod")//只有prod的profile环境下,spring才会加载bean到容器中过去@Component@Slf4j@Profile("prod")publicclassUmpAlarmMqConsumerimplementsIStoppable,InitializingBean{ @Override publicvoidstop(Strin......
  • 带有 Spring Boot 后端的 Vue.js 前端
    概述在开始本教程中,先推荐1个SpringBoot+Vue前后端分离Java项目,本项目是一个大型互联网金融项目,采用SpringBoot,Dubbo微服务的架构,包括多个独立的微服务,micr-common个公共服务,micr-web服务,micr-database数据库服务,micr-pay支付服务,micr-task定时任务。前端技术栈:Vue,Java......
  • springboot整合mybatis
    1,在application.yml中配置点击查看代码#mybatis#配置mapper路径mybatis:mapper-locations:classpath:mapper/*.xml2,在每个DAO接口上面追加@Mapper注解-------------------------------------------------------------增删改查的实现代码application.yml配......
  • springboot 通用限流方案设计与实现
    一、背景限流对于一个微服务架构系统来说具有非常重要的意义,否则其中的某个微服务将成为整个系统隐藏的雪崩因素,为什么这么说?举例来讲,某个SAAS平台有100多个微服务应用,但是作为底层的某个或某几个应用来说,将会被所有上层应用频繁调用,业务高峰期时,如果底层应用不做限流处理,该应用......
  • SpringBoot 2 种方式快速实现分库分表,轻松拿捏!
    大家好,我是小富~(一)好好的系统,为什么要分库分表?(二)分库分表的21条法则,hold住!本文是《分库分表ShardingSphere5.x原理与实战》系列的第三篇文章,本文将为您介绍ShardingSphere的一些基础特性和架构组成,以及在Springboot环境下通过JAVA编码和Yml配置两种方式快速实现分库......
  • idea springboot本地打包配置
    cleanpackage-plrenren-admin-am-amd......
  • springboot入门教程,大家都是怎么学习的?
     学习SpringBoot可以帮助你提高Java后端开发的效率和质量,更快速地构建应用程序,并与当前的开发趋势保持一致。不过,建议你始终关注最新的版本和技术发展,及时了解并学习最新的特性和最佳实践。SpringBoot入门教程对于初学者来说是非常好学的。B站上动力节点王妈妈的springboot3教程......
  • springboot入门教程,大家都是怎么学习的?
    ​学习SpringBoot可以帮助你提高Java后端开发的效率和质量,更快速地构建应用程序,并与当前的开发趋势保持一致。不过,建议你始终关注最新的版本和技术发展,及时了解并学习最新的特性和最佳实践。​Springboot对于初学者来说是非常好学的。B站上动力节点王妈妈的springboot3教程......
  • 教你如何用Vue3搭配Spring Framework
    摘要:在本文中,我们将介绍如何使用Vue3和SpringFramework进行开发,并创建一个简单的TodoList应用程序。本文分享自华为云社区《Vue3搭配SpringFramework开发【Vue3应用程序实战】》,作者:黎燃。一、介绍Vue3和SpringFramework都是现代Web应用程序开发中最流行的框架之一。Vue3是一个......
  • springboot3视频教程,很多可用的教学资源
    不得不说,学习SpringBoot是非常有必要的,尤其是对于Java后端开发人员来说。SpringBoot是基于SpringFramework的快速开发框架,通过自动配置和约定优于配置的原则,大大简化了Spring应用的开发和部署。它提供了丰富的功能和开箱即用的特性,可以帮助开发者快速搭建高效、可靠的企业级应用......