亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringSecurity多認(rèn)證器配置多模式登錄自定義認(rèn)證器方式

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

首先說(shuō)下項(xiàng)目使用背景

A服務(wù) 和B服務(wù) 都在項(xiàng)目中 認(rèn)證服務(wù)是一個(gè)公共模塊 需要多個(gè)認(rèn)證器

第一步

我們先說(shuō)說(shuō) WebSecurityConfigBugVip.class

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

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

	/**
	  *
	  * 注入 RedisTemplate 
	  * 
	  */	
    @Bean
    public RedisTemplate redisTemplateInit() {
        //設(shè)置序列化Key的實(shí)例化對(duì)象
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //設(shè)置序列化Value的實(shí)例化對(duì)象
        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)一處理類(lèi)
                .and().csrf().disable()//跨域請(qǐng)求處理我在網(wǎng)管那邊處理了所以這里不做處理
                .addFilterAt(tokenLoginFilter(), UsernamePasswordAuthenticationFilter.class)//登錄Filter
                .authorizeRequests()//配置需要放行的請(qǐng)求
                .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")//平臺(tái)端退出
                .and().logout().logoutUrl("/admin/acl/logout")//租戶(hù)段推出
                .addLogoutHandler(new TokenLogoutHandler(tokenManager, redisTemplate)).and()//退出登錄的邏輯處理類(lèi)  實(shí)現(xiàn)的是LogoutHandler接口
                .addFilter(new TokenAuthenticationFilter(authenticationManager(), tokenManager, redisTemplate)).httpBasic();//設(shè)置訪問(wèn)過(guò)濾器
    }
    /**
      *
      *登錄過(guò)濾器
      */
    @Bean
    public TokenLoginFilter tokenLoginFilter() {
        TokenLoginFilter filter = new TokenLoginFilter();
        filter.setAuthenticationManager(authenticationManager);
        return filter;
    }

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

第二步

說(shuō)一下 TokenLoginFilter.class 這個(gè)類(lèi)中主要作用是 分派驗(yàn)證器

public class TokenLoginFilter extends AbstractAuthenticationProcessingFilter {
	//登錄地址
    public TokenLoginFilter() {
    	//注入的時(shí)候設(shè)置
        super(new AntPathRequestMatcher("/bugVip/acl/login", "POST"));
    }
    @Autowired
    private TokenManager tokenManager;
    @Autowired
    private RedisCache redisTemplate;
    // 令牌有效期(默認(rèn)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);
        //處理認(rèn)證器
        AbstractAuthenticationToken authRequest = null;
        switch(user.getType()) {
            //租戶(hù)登錄
            case "1":
                authRequest = new TenantAuthenticationToken(user.getUsername(), user.getPassword());
                break;
            //平臺(tái)登錄
            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è)置在線用戶(hù)
     * @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()));
    }



}

我們先說(shuō)一下第一個(gè)認(rèn)證器

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

@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);
        //密碼比對(duì)
        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));
    }
}

第二個(gè)認(rèn)證器

TenantDetailsAuthenticationProvider.class 都是implements 接口 AuthenticationProvider

@Component
public class TenantDetailsAuthenticationProvider implements AuthenticationProvider {
    @Autowired
    private UserDetailServicesTenant userDetailServicesTenant;
    @Autowired
    private RedisCache redisTemplate;
    @Autowired
    private AsyncFactory asyncFactory;
    /**
     * 認(rèn)證器
     * @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對(duì)象,則返回true
     * @param authentication
     * @return
     */
    @Override
    public boolean supports(Class<?> authentication) {
        return (TenantAuthenticationToken.class.isAssignableFrom(authentication));
    }
}

最后再貼一下 services 的代碼

//租戶(hù)的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("租戶(hù)不存在");
        }
        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("用戶(hù)名不存在");
        }
        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;
    }
}

本次項(xiàng)目中 租戶(hù)和平臺(tái)端 服務(wù)都要走 公共模塊SpringSecurity 去認(rèn)證。自定義認(rèn)證器可以繼續(xù)加(業(yè)務(wù)場(chǎng)景需要的時(shí)候)

下面是我的SpringSecurity 公共模塊

感興趣的可以嘗試下。。。多認(rèn)證器

總結(jié)

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

相關(guān)文章

最新評(píng)論