在A系统中自动登录B系统,通过内嵌iframe进行B系统的免密自动登录进行实现

光是下面的代码只能实现相同ip不同端口的跨域iframe自动登录,如果是不同域名的跨域除了下面的代码之外还需要借助nginx的代理,将不同域名的跨域转换为相同ip不同端口的跨域,nginx代理在附一

下面的为A系统登录后跳转的首个页面,在A系统的页面中内嵌iframe,对B系统进行免密自动登录

!<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
<iframe src="http://localhost:9090/jeeplus_war/a/unifiedAuthentication/zzz?cid=admin"></iframe>
</body>
</html>

B系统进行自动登录的接口

@Controller
@RequestMapping(value = "unifiedAuthentication")
public class UnifiedAuthenticationController extends BaseController {


    @RequestMapping(value = "zzz")
    public String singleLoginzz(HttpServletRequest request,HttpServletResponse response,String cid) {
                //TODO 在实际项目中需要在这个接口中添加数字签名认证,保证系统的安全性
        Subject currentUser = SecurityUtils.getSubject();
        //在这里进行shiro框架的免密自动登录
        currentUser.login(new UsernamePasswordToken(cid,"这个密码是随便填的,后续登录验证中并没有使用到".toCharArray(),true));
        //进行在第三方进行自动登录时,由于是在iframe中进行的跨域名访问,没有设置cookie的权限,因此需要添加下面两行代码
        response.setHeader("Set-Cookie", "Key=Value;SameSite=None;Secure");
        response.setHeader("Access-Control-Allow-Origin","*");
        return "redirect:"+"/";
    }

}

B系统的UsernamePasswordToken需要设置可以免除密码的登录

public class UsernamePasswordToken extends org.apache.shiro.authc.UsernamePasswordToken {


   private static final long serialVersionUID = 1L;


   private String captcha;
   private boolean mobileLogin;
   private boolean noPassword;


   public boolean isNoPassword() {
      return noPassword;
   }


   public void setNoPassword(boolean noPassword) {
      this.noPassword = noPassword;
   }


   public UsernamePasswordToken() {
      super();
   }
   public UsernamePasswordToken(String username, char[] password,boolean noPassword) {
      super(username,password);
      this.noPassword=noPassword;
   }


   public UsernamePasswordToken(String username, char[] password,
         boolean rememberMe, String host, String captcha, boolean mobileLogin) {
      super(username, password, rememberMe, host);
      this.captcha = captcha;
      this.mobileLogin = mobileLogin;
   }


   public String getCaptcha() {
      return captcha;
   }


   public void setCaptcha(String captcha) {
      this.captcha = captcha;
   }


   public boolean isMobileLogin() {
      return mobileLogin;
   }
   
}

下面为B系统免密登录相关代码

B系统的自定义实现的验证比较器HashedCredentialsMatcherAndNoPassword

package com.jeeplus.modules.sys.security;


import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SaltedAuthenticationInfo;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.codec.Hex;
import org.apache.shiro.crypto.hash.AbstractHash;
import org.apache.shiro.crypto.hash.Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.StringUtils;


/**
* @author: wyj
* @date: 2021/06/25
*/
public class HashedCredentialsMatcherAndNoPassword extends SimpleCredentialsMatcher {
    private String hashAlgorithm;
    private int hashIterations;
    private boolean hashSalted;
    private boolean storedCredentialsHexEncoded;


    public HashedCredentialsMatcherAndNoPassword() {
        this.hashAlgorithm = null;
        this.hashSalted = false;
        this.hashIterations = 1;
        this.storedCredentialsHexEncoded = true;
    }


    public HashedCredentialsMatcherAndNoPassword(String hashAlgorithmName) {
        this();
        if (!StringUtils.hasText(hashAlgorithmName)) {
            throw new IllegalArgumentException("hashAlgorithmName cannot be null or empty.");
        } else {
            this.hashAlgorithm = hashAlgorithmName;
        }
    }


    public String getHashAlgorithmName() {
        return this.hashAlgorithm;
    }


    public void setHashAlgorithmName(String hashAlgorithmName) {
        this.hashAlgorithm = hashAlgorithmName;
    }


    public boolean isStoredCredentialsHexEncoded() {
        return this.storedCredentialsHexEncoded;
    }


    public void setStoredCredentialsHexEncoded(boolean storedCredentialsHexEncoded) {
        this.storedCredentialsHexEncoded = storedCredentialsHexEncoded;
    }


    /** @deprecated */
    @Deprecated
    public boolean isHashSalted() {
        return this.hashSalted;
    }


    /** @deprecated */
    @Deprecated
    public void setHashSalted(boolean hashSalted) {
        this.hashSalted = hashSalted;
    }


    public int getHashIterations() {
        return this.hashIterations;
    }


    public void setHashIterations(int hashIterations) {
        if (hashIterations < 1) {
            this.hashIterations = 1;
        } else {
            this.hashIterations = hashIterations;
        }


    }


    /** @deprecated */
    @Deprecated
    protected Object getSalt(AuthenticationToken token) {
        return token.getPrincipal();
    }


    protected Object getCredentials(AuthenticationInfo info) {
        Object credentials = info.getCredentials();
        byte[] storedBytes = this.toBytes(credentials);
        if (credentials instanceof String || credentials instanceof char[]) {
            if (this.isStoredCredentialsHexEncoded()) {
                storedBytes = Hex.decode(storedBytes);
            } else {
                storedBytes = Base64.decode(storedBytes);
            }
        }


        AbstractHash hash = this.newHashInstance();
        hash.setBytes(storedBytes);
        return hash;
    }

//免密登录的修改
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        Object tokenHashedCredentials = this.hashProvidedCredentials(token, info);
        Object accountCredentials = this.getCredentials(info);
        UsernamePasswordToken token1 = (UsernamePasswordToken) token;
        if(token1.isNoPassword()){
            return true;
        }
        return this.equals(tokenHashedCredentials, accountCredentials);
    }


    protected Object hashProvidedCredentials(AuthenticationToken token, AuthenticationInfo info) {
        Object salt = null;
        if (info instanceof SaltedAuthenticationInfo) {
            salt = ((SaltedAuthenticationInfo)info).getCredentialsSalt();
        } else if (this.isHashSalted()) {
            salt = this.getSalt(token);
        }


        return this.hashProvidedCredentials(token.getCredentials(), salt, this.getHashIterations());
    }


    private String assertHashAlgorithmName() throws IllegalStateException {
        String hashAlgorithmName = this.getHashAlgorithmName();
        if (hashAlgorithmName == null) {
            String msg = "Required 'hashAlgorithmName' property has not been set.  This is required to execute the hashing algorithm.";
            throw new IllegalStateException(msg);
        } else {
            return hashAlgorithmName;
        }
    }


    protected Hash hashProvidedCredentials(Object credentials, Object salt, int hashIterations) {
        String hashAlgorithmName = this.assertHashAlgorithmName();
        return new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
    }


    protected AbstractHash newHashInstance() {
        String hashAlgorithmName = this.assertHashAlgorithmName();
        return new SimpleHash(hashAlgorithmName);
    }
}

B系统的realm中指定使用上面的比较器

SystemAuthorizingRealm

@Service
//@DependsOn({"userMapper","roleMapper","menuMapper"})
public class SystemAuthorizingRealm extends AuthorizingRealm {
    @PostConstruct
   public void initCredentialsMatcher() {
//    HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(SystemService.HASH_ALGORITHM);
      HashedCredentialsMatcherAndNoPassword matcher = new HashedCredentialsMatcherAndNoPassword(SystemService.HASH_ALGORITHM);
      matcher.setHashIterations(SystemService.HASH_INTERATIONS);
      setCredentialsMatcher(matcher);
   }
}

附一

通过nginx将不同域名的跨域转换为相同ip不同端口的跨域

A系统地址:http://888.888.888:7070

B系统地址:http://999.999:999:8080

在nginx.conf中配置代理

    upstream bserver{            
       #B系统的ip地址:B系统的端口号                                             
        server 999.999:999:8080;                                                
        keepalive 2000;
    }
    server {
        #与A系统不同的端口号
        listen       9000;                                                         
        server_name  localhost;                                               
        client_max_body_size 1024M;

        location / {
            proxy_pass http://bserver/;
            proxy_set_header Host $host:$server_port;
        }
    }

在A系统中嵌入iframe的页面

!<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
<iframe  src="http://888.888.888:9000/jeeplus_war/a/unifiedAuthentication/zzz?cid=admin"></iframe>


</body>
</html>

整个流程为访问A系统:http://888.888.888:7070,A系统的iframe页面去请求http://888.888.888:9000,通过nginx请求转发到B系统http://999.999:999:8080

  • 4
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Web自动化测试切换到iframe内嵌框架)时,您可以使用Selenium提供的`switch_to.frame()`方法。以下是一个示例代码: ```python from selenium import webdriver # 启动浏览器 driver = webdriver.Chrome() try: # 打开网页 driver.get("https://example.com") # 切换到iframe iframe = driver.find_element_by_css_selector("iframe[name='iframe_name']") driver.switch_to.frame(iframe) # 在iframe执行操作 # ... # 切换回主页面 driver.switch_to.default_content() # 在主页面执行其他操作 # ... finally: # 关闭浏览器 driver.quit() ``` 在这个示例代码,我们首先启动了Chrome浏览器。 然后,使用`driver.get()`方法打开了一个网页(示例的URL为https://example.com)。 接下来,使用`driver.find_element_by_css_selector()`方法找到要切换的iframe元素。在示例,我们使用了CSS选择器来定位iframe,您可以根据实际情况使用其他定位方式。 然后,使用`driver.switch_to.frame()`方法切换到该iframe。我们将找到的iframe元素作为参数传递给`switch_to.frame()`方法。 在切换到iframe后,您可以在其执行需要的操作。 完成在iframe的操作后,使用`driver.switch_to.default_content()`方法切换回主页面。 最后,在`finally`块,我们使用`driver.quit()`关闭浏览器。 请注意,示例使用的是Chrome浏览器和CSS选择器,您可以根据实际情况使用其他浏览器和定位方式。您还可以根据具体需求进行操作的扩展和修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值