Saiku调用WS接口

关于saiku集成系统单点登录告一段落,始终没想好怎么去做,主要是因为saiku有自己的权限定义,一直没想好关于saiku本身的权限信息以及用户信息怎么处理(在这里笔者希望已实现saiku单点登录的大佬不吝赐教,感激~)

这里实现了在saiku源码里面调用公司内部的WS接口来验证登录时的密码信息(因为saiku本身未使用dubbo,所以无法直接通过maven引入dubbo包去调用接口)

如果已查看了saiku登录源码追踪(十三)我们就已经大概知道saiku登录时代码执行过程啦,接下来我们就来更改这里的密码校验,调用其他组件的WS接口验证登录

>>调用WS接口

1.在saiku-webapp项目下 找到 WEB-INF/applicationContext-spring-security-jdbc.xml 文件

作出以下更改,替换原来的bean信息,将原来的 org.springframework.security.authentication.dao.DaoAuthenticationProvider 类 替换为自己定义的 org.saiku.service.util.security.authentication.UmServiceProvider 类

 <!--
  <bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService">
<ref bean="userDetailsService" />
</property>
<property name="passwordEncoder">
<ref bean="passwordEncoder" />
</property>
</bean>
-->
<bean id="daoAuthenticationProvider"
class="org.saiku.service.util.security.authentication.UmServiceProvider">
<property name="userDetailsService">
<ref bean="userDetailsService" />
</property>
<property name="passwordEncoder">
<ref bean="passwordEncoder" />
</property>
</bean>

 

2.org.saiku.service.util.security.authentication.UmServiceProvider 类定义在saiku-service项目下的 对应包(org.saiku.service.util.security.authentication.)路径下

内容如下:(内容上基本语原来的DaoAuthenticationProvider 保持一致,更改密码校验方法:additionalAuthenticationChecks(UserDetails userDetails,UsernamePasswordAuthenticationToken authentication))

思路: 注释掉源代码中的密码校验方法passwordEncoder.isPasswordValid

    新增自己的密码校验方法: validatePassword(UserDetails userDetails,UsernamePasswordAuthenticationToken authentication,Object salt)

/*密码校验思路:
1.先判断密码是不是固定密码值,从properties文件中获取的自定义密码信息(我这里是因为嵌入系统时有用到固定密码对应用户以及角色信息气分享saiku数据信息所以才有,如果不需要可以去掉第一个if中的判断 fixedPassword)   
2.再判断密码是否满足 WS接口(WS是公司自定义的相关接口信息,通过jar包引入saiku去调用的,下面会做出相应解析)    
3.以上两种都不符合时,调用saiku自己的密码校验,如果失败就校验失败了。(以上任意一种校验方式成功都会成功登录哦)
*/

UmServiceProvider.java

package org.saiku.service.util.security.authentication;

import org.saiku.service.util.GetFixedPasswordUtil;
import org.saiku.service.util.UMLoginWSUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.authentication.dao.SaltSource;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.authentication.encoding.PlaintextPasswordEncoder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.util.Assert; import com.imodule.ws.soa.um.result.xsd.UmLoginResult; import clover.org.apache.commons.lang.StringUtils; public class UmServiceProvider extends AbstractUserDetailsAuthenticationProvider {
// ~ Static fields/initializers
// ===================================================================================== /**
* The plaintext password used to perform
* {@link PasswordEncoder#isPasswordValid(String, String, Object)} on when the user is
* not found to avoid SEC-2056.
*/
private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword"; // ~ Instance fields
// ================================================================================================ private PasswordEncoder passwordEncoder; /**
* The password used to perform
* {@link PasswordEncoder#isPasswordValid(String, String, Object)} on when the user is
* not found to avoid SEC-2056. This is necessary, because some
* {@link PasswordEncoder} implementations will short circuit if the password is not
* in a valid format.
*/
private String userNotFoundEncodedPassword; private SaltSource saltSource; private UserDetailsService userDetailsService; private GetFixedPasswordUtil getFixedPasswordUtil; public UmServiceProvider() {
setPasswordEncoder(new PlaintextPasswordEncoder());
} // ~ Methods
// ========================================================================================================
/*密码校验思路: 1.先判断密码是不是固定密码值,从properties文件中获取的自定义密码信息(我这里是因为嵌入系统时有用到固定密码对应用户以及角色信息气分享saiku数据信息所以才有,如果不需要可以去掉第一个if中的判断 fixedPassword)
  2.再判断密码是否满足 WS接口(WS是公司自定义的相关接口信息,通过jar包引入saiku去调用的,下面会做出相应解析)
3.以上两种都不符合时,调用saiku自己的密码校验,如果失败就校验失败了。(以上任意一种校验方式成功都会成功登录哦)
*/
private void validatePassword(UserDetails userDetails,UsernamePasswordAuthenticationToken authentication,Object salt){
getFixedPasswordUtil = new GetFixedPasswordUtil();
UMLoginWSUtil umloginWS = new UMLoginWSUtil(); String presentedPassword = authentication.getCredentials().toString(); // get user input password
String fixedPassword = getFixedPasswordUtil.getSaikuUserPassword();
if(StringUtils.isNotBlank(fixedPassword) && fixedPassword.equals(presentedPassword)){
logger.debug("Authentication successs: password match fixed value which store in properties file.");
}else {
//authentication.getName(): user input userid
UmLoginResult umloginResult = umloginWS.getUmLoginWS(authentication.getName(), presentedPassword);
//successs: umloginResult.getResultStatus()=0, fail:umloginResult.getResultStatus()=2
if(umloginResult.getResultStatus().equals("0")){// successs
logger.debug("Authentication success: password match stored value in um Database");
}else{
// if not match properties and um system,use saiku self validator to validate password.
if (!passwordEncoder.isPasswordValid(userDetails.getPassword(),
presentedPassword, salt)) {
logger.debug("Authentication failed: password does not match stored value(neither in properteis nor um system or saiku db.)");
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}
}
}
} @SuppressWarnings("deprecation")
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
Object salt = null; if (this.saltSource != null) {
salt = this.saltSource.getSalt(userDetails);
} if (authentication.getCredentials() == null) {
logger.debug("Authentication failed: no credentials provided"); throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
} validatePassword(userDetails,authentication,salt); /*if (!passwordEncoder.isPasswordValid(userDetails.getPassword(),
presentedPassword, salt)) {
logger.debug("Authentication failed: password does not match stored value"); throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}*/
} protected void doAfterPropertiesSet() throws Exception {
Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
} protected final UserDetails retrieveUser(String username,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
UserDetails loadedUser; try {
loadedUser = this.getUserDetailsService().loadUserByUsername(username);
}
catch (UsernameNotFoundException notFound) {
if (authentication.getCredentials() != null) {
String presentedPassword = authentication.getCredentials().toString();
passwordEncoder.isPasswordValid(userNotFoundEncodedPassword,
presentedPassword, null);
}
throw notFound;
}
catch (Exception repositoryProblem) {
throw new InternalAuthenticationServiceException(
repositoryProblem.getMessage(), repositoryProblem);
} if (loadedUser == null) {
throw new InternalAuthenticationServiceException(
"UserDetailsService returned null, which is an interface contract violation");
}
return loadedUser;
} /**
* Sets the PasswordEncoder instance to be used to encode and validate passwords. If
* not set, the password will be compared as plain text.
* <p>
* For systems which are already using salted password which are encoded with a
* previous release, the encoder should be of type
* {@code org.springframework.security.authentication.encoding.PasswordEncoder}.
* Otherwise, the recommended approach is to use
* {@code org.springframework.security.crypto.password.PasswordEncoder}.
*
* @param passwordEncoder must be an instance of one of the {@code PasswordEncoder}
* types.
*/
public void setPasswordEncoder(Object passwordEncoder) {
Assert.notNull(passwordEncoder, "passwordEncoder cannot be null"); if (passwordEncoder instanceof PasswordEncoder) {
setPasswordEncoder((PasswordEncoder) passwordEncoder);
return;
} if (passwordEncoder instanceof org.springframework.security.crypto.password.PasswordEncoder) {
final org.springframework.security.crypto.password.PasswordEncoder delegate = (org.springframework.security.crypto.password.PasswordEncoder) passwordEncoder;
setPasswordEncoder(new PasswordEncoder() {
public String encodePassword(String rawPass, Object salt) {
checkSalt(salt);
return delegate.encode(rawPass);
} public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
checkSalt(salt);
return delegate.matches(rawPass, encPass);
} private void checkSalt(Object salt) {
Assert.isNull(salt,
"Salt value must be null when used with crypto module PasswordEncoder");
}
}); return;
} throw new IllegalArgumentException(
"passwordEncoder must be a PasswordEncoder instance");
} private void setPasswordEncoder(PasswordEncoder passwordEncoder) {
Assert.notNull(passwordEncoder, "passwordEncoder cannot be null"); this.userNotFoundEncodedPassword = passwordEncoder.encodePassword(
USER_NOT_FOUND_PASSWORD, null);
this.passwordEncoder = passwordEncoder;
} protected PasswordEncoder getPasswordEncoder() {
return passwordEncoder;
} /**
* The source of salts to use when decoding passwords. <code>null</code> is a valid
* value, meaning the <code>DaoAuthenticationProvider</code> will present
* <code>null</code> to the relevant <code>PasswordEncoder</code>.
* <p>
* Instead, it is recommended that you use an encoder which uses a random salt and
* combines it with the password field. This is the default approach taken in the
* {@code org.springframework.security.crypto.password} package.
*
* @param saltSource to use when attempting to decode passwords via the
* <code>PasswordEncoder</code>
*/
public void setSaltSource(SaltSource saltSource) {
this.saltSource = saltSource;
} protected SaltSource getSaltSource() {
return saltSource;
} public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
} protected UserDetailsService getUserDetailsService() {
return userDetailsService;
}
}

3.关于从配置文件中读取固定密码信息。 saikuUser.properties中读取 fixedPassword

在saiku-service中新建Util类:  /saiku-service/src/main/java/org/saiku/service/util/GetFixedPasswordUtil.java

package org.saiku.service.util;

import java.io.FileInputStream;
import java.io.InputStream;
import java.rmi.RemoteException;
import java.util.Properties; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import com.imodule.ws.soa.um.UmSoaPortTypeProxy;
import com.imodule.ws.soa.um.result.xsd.UmLoginResult; /**
* Get password from properties file,for validate password.
* ps: properties file path keep on with this Class path .
* @author S0111
*
*/
public class GetFixedPasswordUtil { private String SAIKU_USER_PASSWORD = "saikuUserPassword";
private String FILE_NAME = "saikuUser.properties";
// FileInputStream in = null;
InputStream ins = null;
String saikuUserPassword = null;
protected final Log logger = LogFactory.getLog(getClass()); /**
* Get local password from properties file.
* @return
*/
public String getSaikuUserPassword(){
try{
Properties properties = new Properties();
// ins = new FileInputStream(this.getClass().getResource("/").getPath()+FILE_NAME);
// ins = getClass().getResourceAsStream(FILE_NAME);
ins = GetFixedPasswordUtil.class.getClassLoader().getResourceAsStream(FILE_NAME);
properties.load(ins);
saikuUserPassword = properties.getProperty(SAIKU_USER_PASSWORD);
logger.debug("GetFixedPasswordUtil - getSaikuUserPassword ,read the properties file,password value is:"+saikuUserPassword);
}catch(Exception e){
logger.debug("GetFixedPasswordUtil - getSaikuUserPassword failed, Caused by:"+e);
e.printStackTrace();
}finally{
if(ins != null){
try{
ins.close();
}catch(Exception e){
logger.debug("GetFixedPasswordUtil - getSaikuUserPassword failed, Caused by:"+e);
e.printStackTrace();
}
}
}
return saikuUserPassword; } }

  

相应的在 saiku-service项目中的 src/main/resources目录下新建properties文件: /saiku-service/src/main/resources/saikuUser.properties  (这里表示不管啥用户只有是saiku有的用户,使用密码saiku123都能登录saiku)

saikuUserPassword=saiku123

 

4.关于saiku源码中调用其他WS接口的Util类:/saiku-service/src/main/java/org/saiku/service/util/UMLoginWSUtil.java  

package org.saiku.service.util;

import java.rmi.RemoteException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import com.imodule.ws.soa.um.UmSoaPortTypeProxy;
import com.imodule.ws.soa.um.result.xsd.UmLoginResult;
/**
* Use UM system login interface to validate userid and password
* @author S0111
*
*/
public class UMLoginWSUtil { protected final Log logger = LogFactory.getLog(getClass()); public UmLoginResult getUmLoginWS(String username ,String password){
UmSoaPortTypeProxy um = new UmSoaPortTypeProxy();
UmLoginResult result = null;
try {
result = um.umLogin(username, password);
logger.debug("UMLoginWSUtil - getUmLoginWS,validate userid and password by UM interface success !!!");
} catch (RemoteException e) {
logger.debug("UMLoginWSUtil - getUmLoginWS,validate userid and password by UM interface failed !!!,Caused by:"+e);
e.printStackTrace();
}
return result;
}
}

  

 

5.关于调用其他WS接口验证

首先需要得到WS接口地址信息: http://11.22.33.44:8080/demo-ws/services/demo-soa?wsdl     #这只是个示例地址,每个公司提供的接口地址都不同

验证地址: 在浏览器中输入  http://11.22.33.44:8080/demo-ws/services/demo-soa?wsdl 去访问,正确的WS接口信息会返回 <wsdl:definitions xmlns:wsd ... 等类似信息

使用Eclipse新建Maven项目 saiku-um-ws  (项目命名随自己啦嘻嘻)

右击新建的羡慕 saiku-um-ws  -->  new   --> others  --> 选中下图中的 Web Service Client --> 点击 next

进入如下页面,在Service definition 处输入WS接口地址信息:http://11.22.33.44:8080/demo-ws/services/demo-soa?wsdl   然后点击finish 即可

再进去看就会看到新建的maven项目 saiku-um-ws已经被填充好了

pom.xml中内容如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com.saiku.ws</groupId>
<artifactId>saiku-um-ws</artifactId>
<version>1.0</version>
<packaging>jar</packaging> <name>saiku-um-ws</name>
<url>http://maven.apache.org</url> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> <dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.axis</groupId>
<artifactId>axis</artifactId>
<version>1.4</version>
</dependency> <dependency>
<groupId>javax.xml</groupId>
<artifactId>jaxrpc-api</artifactId>
<version>1.1</version>
</dependency> <dependency>
<groupId>commons-discovery</groupId>
<artifactId>commons-discovery</artifactId>
<version>0.2</version>
</dependency> <dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency> <dependency>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.4.01</version>
</dependency> <dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
<version>1.5.1</version>
</dependency> <dependency>
<groupId>soap</groupId>
<artifactId>soap</artifactId>
<version>2.3</version>
</dependency>
</dependencies>
</project>

  

将saiku-um-ws项目打包:  mvn  clean  install

再将saiku-um-ws相关的依赖引入 saiku-service项目中的 pom.xml即可

  <!-- add in  2019-03-11,for validate password use other system -->
<dependency>
<groupId>com.saiku.ws</groupId>
<artifactId>saiku-um-ws</artifactId>
<version>0.0.1-SNA</version>
</dependency> <dependency>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.4.01</version>
</dependency>

  

最后,重新编译整个saiku项目, mvn clean install 

获取saiku-server下的 target/dist/saiku-server  双击脚本saiku-start.bat 文件 启动saiku就可以啦~~~~~~~~~

  

======================二次更新 关于ws接口打包后的使用 start  20190627==============================

public class TestLogin {

	public static void main(String[] args) {
UmSoaPortTypeProxy um = new UmSoaPortTypeProxy();
UmLoginResult result = null;
try {
result = um.umLogin("test", "111");
System.out.println(result.getResultStatus());
System.out.println(result.getResultStatus().equals("0"));
result = um.umLogin("test", "123");
System.out.println(result.getResultStatus());
System.out.println(result.getResultStatus()=="0");
// logger.debug("UMLoginWSUtil - getUmLoginWS,validate userid and password by UM interface success !!!");
} catch (RemoteException e) {
// logger.debug("UMLoginWSUtil - getUmLoginWS,validate userid and password by UM interface failed !!!,Caused by:"+e);
e.printStackTrace();
}
System.out.println("result:"+result); } }

  

======================二次更新 关于ws接口打包后的使用 end 20190627==============================

Saiku调用WS接口(十四)的更多相关文章

  1. spring boot / cloud (十四) 微服务间远程服务调用的认证和鉴权的思考和设计,以及restFul风格的url匹配拦截方法

    spring boot / cloud (十四) 微服务间远程服务调用的认证和鉴权的思考和设计,以及restFul风格的url匹配拦截方法 前言 本篇接着<spring boot / cloud ...

  2. Atitit 图像处理之编程之类库调用的接口api cli gui ws rest  attilax大总结.docx

    Atitit 图像处理之编程之类库调用的接口api cli gui ws rest  attilax大总结.docx 1. 为什么需要接口调用??1 1.1. 为了方便集成复用模块类库1 1.2. 嫁 ...

  3. 详解C#泛型(二) 获取C#中方法的执行时间及其代码注入 详解C#泛型(一) 详解C#委托和事件(二) 详解C#特性和反射(四) 记一次.net core调用SOAP接口遇到的问题 C# WebRequest.Create 锚点“#”字符问题 根据内容来产生一个二维码

    详解C#泛型(二)   一.自定义泛型方法(Generic Method),将类型参数用作参数列表或返回值的类型: void MyFunc<T>() //声明具有一个类型参数的泛型方法 { ...

  4. “全栈2019”Java第八十四章:接口中嵌套接口详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  5. “全栈2019”Java第六十四章:接口与静态方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  6. [Effective Java 读书笔记] 第三章类和接口 第十三 -- 十四条

    第十三条 使类和成员的可访问性最小化 总得来说,我们应该尽量将成员的访问范围限制到最小!有利于解耦,开发.测试和优化都能够更加独立. 对于成员(域,方法,嵌套类和嵌套接口),有四种可能的访问级别,访问 ...

  7. Chrome浏览器扩展开发系列之十四

    Chrome浏览器扩展开发系列之十四:本地消息机制Native messaging 时间:2015-10-08 16:17:59      阅读:1361      评论:0      收藏:0    ...

  8. javaSE第二十四天

    第二十四天    363 1:多线程(理解)    363 (1)JDK5以后的Lock锁    363 A:定义    363 B:方法:    364 C:具体应用(以售票程序为例)    364 ...

  9. How Tomcat Works(十四)补充

    在How Tomcat Works(十四)中,本人并没有对javax.servlet.Filter及javax.servlet.FilterChain做详细的描述,本文在这里做一下补充 FilterC ...

随机推荐

  1. Session, Token and SSO 有什么区别

    Session, Token and SSO 有什么区别 Basic Compareation Session-based Authentication In Session-based Authen ...

  2. sitecore开发入门之Sitecore字典结构最佳实践

    使用Sitecore时,一个重要的主题是如何为您的网站处理不同的语言和区域.Sitecore对此的回答是使用字典项,它基本上只代表键/值定义.但是,这个字典项可以设置为具有不同的语言版本,这几乎允许您 ...

  3. Java面试题整理---JVM篇

    1.JVM运行时内存区域划分?   2.内存溢出OOM和堆栈溢出SOE的案例.原因.排查及解决?   3.常用的JVM性能监控工具?   4.JVM参数设置?   5.类加载过程?   6.JVM内存 ...

  4. java线程学习之线程创建

    线程是程序控制的一个内部数据流.线程的状态转化如下 或者 在java中创建线程有两种方式: 1.实现runnable接口(这个比较好,推荐这个.原因是:用的时候比较灵活,相比较继承Thread类,用接 ...

  5. 20190402Linux进阶命令week1.2

    Linux常用命令详解(week1_day1_2) aliasunaliasunamesuhostnamehistorywhichwcwwhowhoamipingkillseqdudffreedate ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. Python自然语言处理笔记【二】文本分类之监督式分类的细节问题

    一.选择正确的特征 1.建立分类器的工作中如何选择相关特征,并且为其编码来表示这些特征是首要问题. 2.特征提取,要避免过拟合或者欠拟合 过拟合,是提供的特征太多,使得算法高度依赖训练数据的特性,而对 ...

  8. P4027 [NOI2007]货币兑换(斜率优化dp+cdq分治)

    P4027 [NOI2007]货币兑换 显然,如果某一天要买券,一定是把钱全部花掉.否则不是最优(攒着干啥) 我们设$f[j]$为第$j$天时用户手上最多有多少钱 设$w$为花完钱买到的$B$券数 $ ...

  9. Bugku-CTF之flag在index里

      Day15 flag在index里 http://123.206.87.240:8005/post/      

  10. java.lang.ClassNotFoundException: org.apache.commons.fileupload.FileItemFactory

    运行servler报错 java.lang.NoClassDefFoundError: org/apache/commons/fileupload/FileItemFactory 或 java.lan ...