第三方登录与鉴权快速集成接口插件

  • 文档创建者:秃破天际
  • 编辑次数:1次
  • 最近更新:Leo.Tsai 于 2019-11-11
  • 1. 概述

    1.1 版本

    报表服务器版本

    JAR 包版本

    插件版本

    10.02019-07-18V2.7.1

    1.2 应用场景

    • 绝大部分基于用户名/手机/邮箱、验证码/密码这类的用户名密码变种登录集成场景。

    • 绝大部分基于 token ticket code cookie Authorization 等等的非用户密码登录集成的场景。

    • 绝大部分免登录页登陆直接访问报表的登录集成场景。

    • 绝大部分用户自定义的报表/BI仪表板的访问自定义鉴权场景。

    1.3 功能介绍

    安装插件后,对插件提供的接口进行简单的开发,完成相关登录和鉴权的集成。

    2. 示例

    2.1 插件安装

    点击下载插件:登录&权限集成

    设计器插件安装方法参照 设计器插件管理

    服务器安装插件方法参照 服务器插件管理

    2.2 操作方法

    安装完插件后,用你熟悉的 JAVA IDE 新建一个开发工程,把设计器内的 JAR 包都添加为依赖,然后把设计器插件安装目录下的 fr-plugin-platform-bridge-1.0.jar 添加为依赖。

    这个时候就可以使用插件提供的接口了,先看接口的描述:

    package com.tptj.plugin.hg.fun;

    import com.tptj.plugin.hg.bean.XResult;

    import javax.servlet.http.HttpServletRequest;

    public interface XLogin {
       //配置文件中的标记
       public final static String CONF_TAG = "xlogin";

       //getTag方法返回这个值时表示忽略当前的请求,也就不会走你实现的接口去登陆。
       //主要是很多FR自身请求本身不会携带用户登陆需要的标记,当我们取不到自己需要的标记时,尽量选择返回忽略当前的请求
       //否则所有的请求都可能会走验证,这样本质就跟cas类似了~会筛查所有的请求了
       public final static String IGNORE_THIS_REQUEST = "IGNORE_THIS_REQUEST";

       /**
        * 用于处理所有可能的登陆情况,只要你的TAG满足你的要求就尽情的登陆吧
        * @param req
        * @param username 如果是走产品本身的登陆请求或者单点登陆接口之类的,就会有用户名和密码
        * @param password 同上
        * @param tag getTag方法获取到的标记,主要是因为获取标记本身会涉及请求之类的,为了减少链路,就再传递进来
        * @return 登陆的结果 XResult.success(username); XResult.failure(username).reedirectURL(URL);
        *          登陆失败时可以指定跳转到某个页面去
        *          如果是输入用户名密码登陆的情况(password不为空的时候)
        *          假设需要使用输入的密码去进行登陆验证的话就返回 XResult.success(username).password(password)
        *          否则返回XResult.success(username)就表示忽略密码直接登陆
        */
       public XResult login(HttpServletRequest req, String username, String password, String tag );

       /**
        * 获取你登陆需要的标记,比如你是header里面有token呀或者是请求参数有什么加密的参数呀等等的,如果有多个需要
        * 序列化为一个字符串(自己要能反序列化哟,否则可能在登陆时你自己就识别不出来了)
        * @param req 当前请求
        * @return 获取到的标记  对于获取不到标记的请求,建议直接返回IGNORE_THIS_REQUEST
        */
       public String getTag(HttpServletRequest req);

       //你不需要关心这是啥,当他不存在就好
       public final static String LOGIN_TAG = "X-LOGIN-TAG";
    }


    package com.tptj.plugin.hg.fun;

    import com.tptj.plugin.hg.bean.XResult;

    import javax.servlet.http.HttpServletRequest;

    public interface XAuthorization {

       //配置文件中的标记
       public final static String CONF_TAG = "xauth";

       /**
        * 用于判断模板访问的授权的:也就是当前请求,当前用户(可能没有用户),要访问某个模板或者BI的仪表板是否允许访问
        * 注意:必须开启任意一种模板权限控制,这个接口才能使用
        * @param req       当前请求
        * @param template  模板路径或者仪表板的ID
        * @param username  当前的用户名(不一定有,可能当前就没有登陆FR用户)
        * @return 登陆的结果 XResult.success(username); XResult.failure(username);
        *          如果当前没有用户登陆,又想指定当前的用户名以便在报表中通过fine_username参数引用,可以指定返回的用户名
        *          当然如果已经有FR用户登陆了,这个指定是无效的,这里也不能进行重定向【为了如果有了新的设计会考虑】
        */
       public XResult auth(HttpServletRequest req, String template, String username );
    }

    以上两个接口是核心,注释讲得很清楚,就不单独再解释了,还有一个辅助接口,跟 FineReport 本身的事件接口是一致的,只是这里做了简化不需要开发者再封装插件。

    package com.tptj.plugin.hg.fun;

    import com.fr.decision.webservice.login.LogInOutResultInfo;

    /**
    * 照搬的LogInOutEventProvider接口,但是这个接口使用时需要开发者自行注意一些细节
    * 比如不要在响应里面随便输出什么或者重定向什么的,会导致后续逻辑出问题,写写cookie什么的倒是可以
    * 这个接口主要的场景是用于登陆或者登出后做一些记录或者通知以及同步用的
    */

    public interface XEvent {
       //配置文件中的标记
       public final static String CONF_TAG = "xevent";
       /**
        * 登陆后事件
        * @param result 当前的登陆结果
        */
       public void afterLogin(LogInOutResultInfo result);

       /**
        * 登出后事件
        * @param result 当前的登出结果
        * @return 如果需要重定向的话通过这个返回值提供重定向的链接,否则返回空字符串就可以了
        */
       public String afterLogout(LogInOutResultInfo result);

    }

    阅读完上面的接口我们来看几个登录的实例场景。

    package com.tptj.test;

    import javax.servlet.http.HttpServletRequest;

    import com.fr.log.FineLoggerFactory;
    import com.fr.stable.StringUtils;
    import com.tptj.plugin.hg.bean.XResult;
    import com.tptj.plugin.hg.fun.XLogin;
    import com.tptj.plugin.hg.impl.AbstractXLogin;
    import com.tptj.plugin.hg.sdk.platform.bridge.API;


    /**
    * 本例就以使用手机号作为用户名为例进行讲解
    * @author 秃破天际
    *
    */
    public class Demo1Login extends AbstractXLogin {

       @Override
       public String getTag( HttpServletRequest req ) {
           //因为是默认的登陆,所以我们不存在特殊的登陆标记需要获取,直接返回忽略请求就可以了
           return XLogin.IGNORE_THIS_REQUEST;
       }

       @Override
       public XResult login(HttpServletRequest req, String username, String password, String tag) {
           //这里前方输入的用户名实际是手机号,所以我们需要将手机号转换成真正的用户名进行登陆
           String tu = API.USER.getUsernameByMobile(username);
           if(StringUtils.isNotEmpty(tu)){
               username = tu;
           }
           FineLoggerFactory.getLogger().info("###### login({})",username);
           //如果是邮件转换用户名可以用API.USER.getUsernameByEmail(username);
           //至于密码是否正确我们就交给后面的程序去处理了[根据接口介绍,我们是不忽略密码的,所以把密码直接返回]
           return XResult.success(username).password(password);
       }

    }
    package com.tptj.test;

    import javax.servlet.http.HttpServletRequest;

    import com.fr.log.FineLoggerFactory;
    import com.fr.stable.StringUtils;
    import com.fr.web.utils.WebUtils;
    import com.tptj.plugin.hg.bean.XResult;
    import com.tptj.plugin.hg.fun.XLogin;
    import com.tptj.plugin.hg.impl.AbstractXLogin;
    import com.tptj.plugin.hg.sdk.platform.bridge.API;

    /**
    * 本例我们说明使用非用户名密码体系如何做登陆认证的,比如 ticket code token cookie Authorization 等等等等的
    * @author 秃破天际
    *
    */
    public class Demo2Login extends AbstractXLogin {

       @Override
       public String getTag( HttpServletRequest req ) {
           //假设当请求中存在code参数时我们就需要做某种登陆
           String code = WebUtils.getHTTPRequestParameter(req, "code");
           if( StringUtils.isNotEmpty(code) ){
               return code;
           }
           return XLogin.IGNORE_THIS_REQUEST;
       }

       @Override
       public XResult login(HttpServletRequest req, String username, String password, String tag) {
           String code = tag;//这里的tag就是上面的code
           FineLoggerFactory.getLogger().info("###### login({})",code);
           //本例就简单假设场景,我们的code就是用户名了,实际运用中一般可能是需要进行解密或者是到第三方服务器去做认证的
           if( StringUtils.isEmpty(code) ||  StringUtils.equals( code, XLogin.IGNORE_THIS_REQUEST ) || !API.USER.exist(code) ){
               //认证失败时我们跳转到某个登陆页面去
               return XResult.failure(username).reedirectURL("http://www.baidu.com");
           }
           //认证成功时将要登陆的用户名提供给后面的程序即可
           return XResult.success(code);
       }

    }
    package com.tptj.test;

    import java.util.Date;

    import javax.servlet.http.HttpServletRequest;

    import com.fr.log.FineLoggerFactory;
    import com.fr.stable.StringUtils;
    import com.tptj.plugin.hg.bean.XResult;
    import com.tptj.plugin.hg.impl.AbstractXAuthorization;

    /**
    * 本例我们说明如何自定义的进行cpt/frm BI仪表板的访问权限控制
    *
    * @author 秃破天际
    *
    */
    public class DemoAuth extends AbstractXAuthorization {

       @Override
       public XResult auth(HttpServletRequest req, String template, String username) {
           //比如只要是在时间分钟是奇数时访问系统就允许访问,否则不允许访问
           //如果用户名不存在则,将用户名设置成 zhangsan
           FineLoggerFactory.getLogger().info("###### auth({})",StringUtils.isNotEmpty(username) ? username : "zhangsan");
           int min = new Date().getMinutes();
           if( 1 == min % 2  ){
               return XResult.success( StringUtils.isNotEmpty(username) ? username : "zhangsan" );
           }
           return XResult.failure(username);
       }

    }

    场景都是非常简单的,仅仅是为了说明接口怎么用。

    开发好的类,编译成 class 文件后,放到插件目录下的 classes 文件夹内(如果没有的话需要自己新建),注意要正确对应下面的包路径。

    WEB-INF\plugins\plugin-com.tptj.plugin.hg.platform.bridge.v10-1.0\classes

    然后配置配置文件 。

    WEB-INF\resources\xplatform.properties
    内容如下,就是把各位自己开发的类名配置进去就可以了,3个接口都有默认实现,如果你自己没实现可以填默认接口
    # com.tptj.plugin.hg.dft.DefaultXLogin
    xlogin=com.tptj.test.Demo1Login
    # com.tptj.plugin.hg.dft.DefaultXAuthorization
    xauth=com.tptj.test.DemoAuth
    xevent=com.tptj.plugin.hg.dft.DefaultXEvent

    然后保存配置重启服务器/设计器就可以了

    注:3个接口并非都要实现,你的场景需要什么就实现什么,绝大多数时候只需要实现一个接口就可以满足我们的需要了。

    附件列表


    主题: 部署集成
    • 有帮助
    • 没帮助
    • 只是浏览