欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringSecurity多認證器配置多模式登錄自定義認證器方式

 更新時間:2025年04月06日 11:09:54   作者:青衣畫白扇  
這篇文章主要介紹了SpringSecurity多認證器配置多模式登錄自定義認證器方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

首先說下項目使用背景

A服務(wù) 和B服務(wù) 都在項目中 認證服務(wù)是一個公共模塊 需要多個認證器

第一步

我們先說說 WebSecurityConfigBugVip.class

/**
 * @Author:  Mr_xk
 * @Description: 配置類
 * @Date:  2021/8/1
 **/
@Configuration
@EnableWebSecurity
public class WebSecurityConfigBugVip extends WebSecurityConfigurerAdapter {
	//jwt生成 token 和續(xù)期的類
    private TokenManager tokenManager;
    // 操作redis 
    private RedisTemplate redisTemplate;
    @Autowired
    //租戶服務(wù)的認證器
    private TenantDetailsAuthenticationProvider userDetailsAuthenticationProvider;
    
    @Autowired
    //平臺端的認證器
    private UsernamePasswordAuthenticationProvider usernamePasswordAuthenticationProvider;
    @Autowired
    @Qualifier("authenticationManagerBean")//認證管理器
    private AuthenticationManager authenticationManager;

    /**
     * 裝配自定義的Provider
     * @param auth
     */
    @Override
    public void configure(AuthenticationManagerBuilder auth){
    	//這個為BOSS認證器 (也可以理解為上圖A服務(wù))
        auth.authenticationProvider(userDetailsAuthenticationProvider);
        //這個為Tenant認證器 (B服務(wù))
        auth.authenticationProvider(usernamePasswordAuthenticationProvider);
    }

	/**
	  *
	  * 注入 RedisTemplate 
	  * 
	  */	
    @Bean
    public RedisTemplate redisTemplateInit() {
        //設(shè)置序列化Key的實例化對象
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //設(shè)置序列化Value的實例化對象
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        return redisTemplate;
    }

    @Autowired
    public WebSecurityConfigBugVip(TokenManager tokenManager, RedisTemplate redisTemplate) {
        this.tokenManager = tokenManager;
        this.redisTemplate = redisTemplate;
    }
    /**
     * 配置設(shè)置
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling()
                .authenticationEntryPoint(new UnauthorizedEntryPoint())//未授權(quán)的統(tǒng)一處理類
                .and().csrf().disable()//跨域請求處理我在網(wǎng)管那邊處理了所以這里不做處理
                .addFilterAt(tokenLoginFilter(), UsernamePasswordAuthenticationFilter.class)//登錄Filter
                .authorizeRequests()//配置需要放行的請求
                .antMatchers("/boss/verifi/getCode").permitAll()
                .antMatchers("/boss/verifi/checkVrrifyCode").permitAll()
                .antMatchers("/swagger-resources/**").permitAll()
                .antMatchers("/webjars/**").permitAll()
                .antMatchers("/v2/**").permitAll()
                .antMatchers("/swagger-ui.html/**").permitAll()
                .anyRequest().authenticated()
                .and().logout().logoutUrl("/boss/acl/logout")//平臺端退出
                .and().logout().logoutUrl("/admin/acl/logout")//租戶段推出
                .addLogoutHandler(new TokenLogoutHandler(tokenManager, redisTemplate)).and()//退出登錄的邏輯處理類  實現(xiàn)的是LogoutHandler接口
                .addFilter(new TokenAuthenticationFilter(authenticationManager(), tokenManager, redisTemplate)).httpBasic();//設(shè)置訪問過濾器
    }
    /**
      *
      *登錄過濾器
      */
    @Bean
    public TokenLoginFilter tokenLoginFilter() {
        TokenLoginFilter filter = new TokenLoginFilter();
        filter.setAuthenticationManager(authenticationManager);
        return filter;
    }

    /**
     * 處理注入 AuthenticationManager失敗問題
     * @return
     * @throws Exception
     */
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

第二步

說一下 TokenLoginFilter.class 這個類中主要作用是 分派驗證器

public class TokenLoginFilter extends AbstractAuthenticationProcessingFilter {
	//登錄地址
    public TokenLoginFilter() {
    	//注入的時候設(shè)置
        super(new AntPathRequestMatcher("/bugVip/acl/login", "POST"));
    }
    @Autowired
    private TokenManager tokenManager;
    @Autowired
    private RedisCache redisTemplate;
    // 令牌有效期(默認30分鐘)
    @Value("${token.expireTime}")
    private int expireTime;
    protected static final long MILLIS_SECOND = 1000;

    protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;

    @Override
    public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {
        if (!httpServletRequest.getMethod().equals("POST")) {
            throw new AuthenticationServiceException(
                    "Authentication method not supported: " + httpServletRequest.getMethod());
        }
        User user = new ObjectMapper().readValue( httpServletRequest.getInputStream(), User.class);
        //處理認證器
        AbstractAuthenticationToken authRequest = null;
        switch(user.getType()) {
            //租戶登錄
            case "1":
                authRequest = new TenantAuthenticationToken(user.getUsername(), user.getPassword());
                break;
            //平臺登錄
            case "2":
                authRequest = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
                break;
        }
        setDetails(httpServletRequest, authRequest);
        return this.getAuthenticationManager().authenticate(authRequest);
    }
    protected void setDetails(HttpServletRequest request,
                              AbstractAuthenticationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }

    /**
     * 登錄成功
     * @param req
     * @param res
     * @param chain
     * @param auth
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,
                                            Authentication auth){
        String fastUUID = IdUtils.fastUUID();
        String datakey =(String)req.getAttribute("datakey");
        String token = tokenManager.createToken(fastUUID);
        Collection<? extends GrantedAuthority> principal = auth.getAuthorities();
        List<String> collect = principal.stream().map(e -> e.toString()).collect(Collectors.toList());
        redisTemplate.setCacheObject(RedisConstant.PERRMISSION+fastUUID,collect,expireTime, TimeUnit.MINUTES);
        OnlineUserInfo onlineUserInfo = setonlineUserInfo(token, auth,req,datakey);
        if(StringUtils.isEmpty(datakey)){
            redisTemplate.setCacheObject(RedisConstant.ONLINE_BOSS_INFO+fastUUID,onlineUserInfo,expireTime,TimeUnit.MINUTES);
            ResponseUtil.out(res, R.ok().data("token", token));
        }else{
            redisTemplate.setCacheObject(RedisConstant.ONLINE_INFO+fastUUID,onlineUserInfo,expireTime,TimeUnit.MINUTES);
            ResponseUtil.out(res, R.ok().data("token", token).data("datakey",datakey));
        }
    }
    /**
     * 設(shè)置在線用戶
     * @param token
     * @param authentication
     * @param request
     * @return
     */
    public OnlineUserInfo setonlineUserInfo(String token, Authentication authentication, HttpServletRequest request,String datakey){
        OnlineUserInfo onlineUserInfo = new OnlineUserInfo();
        SecurityUser principal = (SecurityUser) authentication.getPrincipal();
        onlineUserInfo.setSysUser(principal.getSysUser());
        onlineUserInfo.setToken(token);
        onlineUserInfo.setDatakey(datakey);
        onlineUserInfo.setLoginTime(System.currentTimeMillis());
        onlineUserInfo.setExpireTime(System.currentTimeMillis()+expireTime * MILLIS_MINUTE);
        RequestWrapper requestWrapper = new RequestWrapper(request);
        onlineUserInfo.setIpaddr(requestWrapper.getRemoteAddr());
        IpData ipData = IpGetAdders.doPostOrGet();
        onlineUserInfo.setIpadderss(ipData.getCname());
        onlineUserInfo.setUserOs(UserAgentUtil.parse(requestWrapper.getHeader("User-Agent")).getOs().toString());
        onlineUserInfo.setBrowser(UserAgentUtil.parse(requestWrapper.getHeader("User-Agent")).getBrowser().toString());
        return onlineUserInfo;
    }
    /**
     * 登錄失敗
     * @param request
     * @param response
     * @param e
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                              AuthenticationException e) {
        ResponseUtil.out(response, R.error().data("message",e.getMessage()));
    }



}

我們先說一下第一個認證器

UsernamePasswordAuthenticationProvider.class Boos 服務(wù)使用的認證器

@Component
public class UsernamePasswordAuthenticationProvider implements AuthenticationProvider {
    @Autowired
    private UserDetailsServicesBoss userDetailsServicesMy;
    @Autowired
    private AsyncFactory asyncFactory;
    @SneakyThrows
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username =authentication.getName();
        String password = (String) authentication.getCredentials();
        DefaultPasswordEncoder passwordEncoder =new DefaultPasswordEncoder();
        SecurityUser userDetails = userDetailsServicesMy.loadUserByUsername(username);
        //密碼比對
        if(passwordEncoder.encode(password).equals(userDetails.getPassword())){
            UsernamePasswordAuthenticationToken  result = new UsernamePasswordAuthenticationToken (userDetails, null, userDetails.getAuthorities());
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
            RequestContextHolder.setRequestAttributes(requestAttributes,true);
            //這里是設(shè)置登錄日志
            asyncFactory.loginLogSet(username, LogConstant.LOGIN_SUCCESS,LogConstant.LOGIN_LOG ,LogConstant.LOG_INFO,LogConstant.LOGIN_BOSS,"");
            return result;
        }else{
         //這里是設(shè)置登錄日志
            asyncFactory.loginLogSet(username, LogConstant.LOGIN_FAIL,LogConstant.LOGIN_LOG ,LogConstant.LOG_INFO,LogConstant.LOGIN_BOSS,new BadCredentialsException("密碼不正確").toString());
            throw new BadCredentialsException("密碼不正確");
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
    }
}

第二個認證器

TenantDetailsAuthenticationProvider.class 都是implements 接口 AuthenticationProvider

@Component
public class TenantDetailsAuthenticationProvider implements AuthenticationProvider {
    @Autowired
    private UserDetailServicesTenant userDetailServicesTenant;
    @Autowired
    private RedisCache redisTemplate;
    @Autowired
    private AsyncFactory asyncFactory;
    /**
     * 認證器
     * @param authentication
     * @return
     * @throws AuthenticationException
     */
    @SneakyThrows
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = (String) authentication.getCredentials();
        HttpServletRequest request = ServletUtils.getRequest();
        RequestWrapper requestWrapper = new RequestWrapper(request);
        String ip = requestWrapper.getRemoteAddr();
        String datakey = redisTemplate.getCacheMapValue(RedisConstant.TENANT_DATAKEY,ip);
        requestWrapper.setAttribute("datakey",datakey);
        SecurityUser userDetails = userDetailServicesTenant.loadUserByUsername(username,datakey);
        DefaultPasswordEncoder passwordEncoder = new DefaultPasswordEncoder();
        boolean matches = passwordEncoder.matches(passwordEncoder.encode(password), userDetails.getPassword());
        if(matches){
            TenantAuthenticationToken result = new TenantAuthenticationToken(userDetails, "", userDetails.getAuthorities());
            result.setDetails(authentication.getDetails());
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
            RequestContextHolder.setRequestAttributes(requestAttributes,true);

            asyncFactory.loginLogSet(username, LogConstant.LOGIN_SUCCESS,LogConstant.LOGIN_LOG ,LogConstant.LOG_INFO,LogConstant.LOGIN_TENANT,"");
            return result;
        }else{
            asyncFactory.loginLogSet(username, LogConstant.LOGIN_FAIL,LogConstant.LOGIN_LOG ,LogConstant.LOG_INFO,LogConstant.LOGIN_TENANT,new BadCredentialsException("密碼不正確").toString());
            throw new BadCredentialsException("密碼不正確");
        }
    }

    /**
     * 如果該AuthenticationProvider支持傳入的Authentication對象,則返回true
     * @param authentication
     * @return
     */
    @Override
    public boolean supports(Class<?> authentication) {
        return (TenantAuthenticationToken.class.isAssignableFrom(authentication));
    }
}

最后再貼一下 services 的代碼

//租戶的services
@Service
public class UserDetailServicesTenant {
    @Autowired
    private TenantLoginServices tenantLoginServices;

    public SecurityUser loadUserByUsername(String name,String datakey) throws UsernameNotFoundException {
        SysUser tenantUser = tenantLoginServices.findbyTenantname(datakey,name);
        if (ObjectUtils.isEmpty(tenantUser)) {
            throw new UsernameNotFoundException("租戶不存在");
        }
        User usersecurity = new User();
        BeanUtils.copyProperties(tenantUser, usersecurity);
        List<String> authorities= tenantLoginServices.selectPermissionValueByRolerTenant(datakey, tenantUser.getId());
        List<String> collect = authorities.stream().filter(e -> !ObjectUtils.isEmpty(e)).distinct().collect(Collectors.toList());
        collect.add("admin/acl/info");
        collect.add("admin/acl/getmenu");
        collect.add("admin/acl/logout");
        SecurityUser securityUser = new SecurityUser(usersecurity);
        securityUser.setPermissionValueList(collect);
        securityUser.setSysUser(tenantUser);
        securityUser.setLoginType(2);
        return securityUser;
    }
}
//Boss 的servics
@Service
public class UserDetailsServicesBoss {
    @Autowired
    private BossTenantServices loginServices;

    public SecurityUser loadUserByUsername(String name) throws UsernameNotFoundException {
        SysUser  user= loginServices.findbyname(name);
        if(StringUtils.isEmpty(user)){
            throw new UsernameNotFoundException("用戶名不存在");
        }
        User usersecurity = new User();
        BeanUtils.copyProperties(user,usersecurity);
        List<String>  authorities = loginServices.selectPermissionValueByRoler(user.getSysUserRolerId());
        List<String> collect = authorities.stream().filter(e-> !ObjectUtils.isEmpty(e)).distinct().collect(Collectors.toList());
        collect.add("boss/acl/info");
        collect.add("boss/acl/getmenu");
        collect.add("boss/acl/logout");
        SecurityUser securityUser = new SecurityUser(usersecurity);
        securityUser.setPermissionValueList(collect);
        securityUser.setSysUser(user);
        securityUser.setLoginType(1);
        return securityUser;
    }
}

本次項目中 租戶和平臺端 服務(wù)都要走 公共模塊SpringSecurity 去認證。自定義認證器可以繼續(xù)加(業(yè)務(wù)場景需要的時候)

下面是我的SpringSecurity 公共模塊

感興趣的可以嘗試下。。。多認證器

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java后臺返回blob格式的文件流的解決方案

    Java后臺返回blob格式的文件流的解決方案

    在Java后臺開發(fā)中,經(jīng)常會遇到需要返回Blob格式的文件流給前端的情況,Blob是一種二進制大對象類型,可以用于存儲大量的二進制數(shù)據(jù),例如圖片、音頻、視頻等,本文將為你詳細介紹如何在Java后臺中返回Blob格式的文件流,需要的朋友可以參考下
    2024-08-08
  • Java調(diào)用基于Ollama本地大模型的實現(xiàn)

    Java調(diào)用基于Ollama本地大模型的實現(xiàn)

    本文主要介紹了Java調(diào)用基于Ollama本地大模型的實現(xiàn),實現(xiàn)文本生成、問答、文本分類等功能,開發(fā)者可以輕松配置和調(diào)用模型,具有一定的參考價值,感興趣的可以了解一下
    2025-03-03
  • Spring?Boot如何利用攔截器加緩存完成接口防刷操作

    Spring?Boot如何利用攔截器加緩存完成接口防刷操作

    流的需求出現(xiàn)在許多常見的場景中,下面這篇文章主要給大家介紹了關(guān)于Spring?Boot如何利用攔截器加緩存完成接口防刷操作的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-02-02
  • Java9中操作和查詢本地進程信息的示例詳解

    Java9中操作和查詢本地進程信息的示例詳解

    這篇文章主要為大家詳細介紹了Java9中操作和查詢本地進程信息的相關(guān)知識,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03
  • Java使用設(shè)計模式中迭代器模式構(gòu)建項目的代碼結(jié)構(gòu)示例

    Java使用設(shè)計模式中迭代器模式構(gòu)建項目的代碼結(jié)構(gòu)示例

    這篇文章主要介紹了Java使用設(shè)計模式中迭代器模式構(gòu)建項目的代碼結(jié)構(gòu)示例,迭代器模式能夠?qū)υL問者隱藏對象的內(nèi)部細節(jié),需要的朋友可以參考下
    2016-05-05
  • 深入了解Java atomic原子類的使用方法和原理

    深入了解Java atomic原子類的使用方法和原理

    這篇文章主要介紹了深入了解Java atomic原子類的使用方法和原理,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,,需要的朋友可以參考下
    2019-06-06
  • jpanel設(shè)置背景圖片的二個小例子

    jpanel設(shè)置背景圖片的二個小例子

    這篇文章主要介紹了jpanel設(shè)置背景圖片的二個小例子,實現(xiàn)了動態(tài)加載圖片做背景的方法,需要的朋友可以參考下
    2014-03-03
  • 解決使用RestTemplate時報錯RestClientException的問題

    解決使用RestTemplate時報錯RestClientException的問題

    這篇文章主要介紹了解決使用RestTemplate時報錯RestClientException的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • JavaWeb請求轉(zhuǎn)發(fā)和請求包含實現(xiàn)過程解析

    JavaWeb請求轉(zhuǎn)發(fā)和請求包含實現(xiàn)過程解析

    這篇文章主要介紹了JavaWeb請求轉(zhuǎn)發(fā)和請求包含實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-02-02
  • Java設(shè)計模式中單一職責(zé)原則詳解

    Java設(shè)計模式中單一職責(zé)原則詳解

    這篇文章主要介紹了Java設(shè)計模式中單一職責(zé)原則詳解,單一職責(zé)原則 (SRP) 是軟件設(shè)計中的一個重要原則,它要求每個類只負責(zé)一個職責(zé),需要的朋友可以參考下
    2023-05-05

最新評論