后台登录-PC移动端通用

  • 文档创建者:Arri
  • 编辑次数:4次
  • 最近更新:Arri 于 2020-03-31
  • 1. 概述

    1.1 问题描述

    当用户想要将 FineReport 报表工程集成自己的系统时,可以在登录自己系统的同时登录报表平台。例如用户集成了 OA 系统和平台系统,想要在登录 OA 的同时就登录平台,此时需要使用到单点登录。单点登录的方法除了前端 Ajax 单点( Ajax 跨域异步单点登录 )以外,还可以使用后台登录的方式。做好后台登录后,在 OA 等其他系统访问报表平台或报表地址,将无需重复登录。

    1.2 实现思路

    通过在 web.xml 中增加拦截请求,Java 调用 FineReport 后台登录接口,来实现后台登录。

    2. 操作方法

    2.1 web.xml

    在 web.xml 中增加 FineReport 相关地址的拦截代码:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app
       xmlns="http://java.sun.com/xml/ns/j2ee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
       version="2.4">
      <display-name>Template WebApp</display-name>
       
        <mime-mapping>
      <extension>msi</extension>
      <mime-type>application/x-msi</mime-type>
      </mime-mapping>
         
     <filter>   
        <filter-name>Auther</filter-name>   
        <filter-class>com.fr.io.AuthFilter</filter-class>   
    </filter>   
    <filter-mapping>   
        <filter-name>Auther</filter-name>   
        <url-pattern>/decision/view/report</url-pattern>  //拦截report 
    </filter-mapping> 
    <filter-mapping>   
        <filter-name>Auther</filter-name>   
        <url-pattern>/decision/view/form</url-pattern>    //拦截form
    </filter-mapping>
    <filter-mapping>   
        <filter-name>Auther</filter-name>   
        <url-pattern>/decision</url-pattern>    //拦截pc平台
    </filter-mapping>
    <filter-mapping>   
        <filter-name>Auther</filter-name>   
        <url-pattern>/decision/url/mobile</url-pattern>  //拦截移动端平台
    </filter-mapping> 
    </web-app>

    2.2 Java 代码

    在 Java 中调用后台登录接口,有两种方式:cookie 和 session,根据实际情况选其一即可。

    2.2.1 cookie

    package com.fr.io;

    import com.fr.data.NetworkHelper;
    import com.fr.decision.authority.data.User;
    import com.fr.decision.mobile.terminal.TerminalHandler;
    import com.fr.decision.webservice.exception.user.UserNotExistException;
    import com.fr.decision.webservice.utils.DecisionServiceConstants;
    import com.fr.decision.webservice.v10.login.LoginService;
    import com.fr.decision.webservice.v10.login.TokenResource;
    import com.fr.decision.webservice.v10.user.UserService;
    import com.fr.general.ComparatorUtils;
    import com.fr.log.FineLoggerFactory;
    import com.fr.security.JwtUtils;
    import com.fr.stable.StringUtils;
    import com.fr.stable.web.Device;

    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Arrays;
    import java.util.List;


    public class AuthFilter implements Filter {

        // 携带用户名的参数名称
        private static final String userNameParameter = "sysadmin";

        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

            HttpServletRequest request = (HttpServletRequest) servletRequest;
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            // 这个地方username的获取,根据具体你请求的时候把username放在哪了来确定
            //String username = request.getParameter(userNameParameter);
            String username = "sysadmin";
            FineLoggerFactory.getLogger().info("username="+username);
            // 用户名参数不为空时,走登录逻辑
            if (StringUtils.isNotEmpty(username)) {
                // 获取该用户名的token
                String oldToken = TokenResource.COOKIE.getToken(request);  
                FineLoggerFactory.getLogger().info("oldTokenSession=="+oldToken);
                System.out.println("oldtoken==="+oldToken);
                // 无token/token失效,则走登录逻辑
                if (StringUtils.isEmpty(oldToken) || !checkTokenValid(request, oldToken, username)) {
                    try {
                        // 系统中无该用户则抛出异常
                        User user = UserService.getInstance().getUserByUserName(username);
                        FineLoggerFactory.getLogger().info("user="+user);
                        System.out.println("user==="+user);
                        if (user == null) {
                            throw new UserNotExistException();
                        }
                        // 将token写入response
                        String token = LoginService.getInstance().login(request, response, username);
                        // 将token写入request
                        request.setAttribute(DecisionServiceConstants.FINE_AUTH_TOKEN_NAME, token);
                        //filterChain.doFilter(request,response);
                    } catch (Exception e) {
                        FineLoggerFactory.getLogger().error(e.getMessage(), e);
                    }
                }
                else {
                    // 用户名参数为空,直接doFilter
                    filterChain.doFilter(request,response);
                }
                
                // 检查用户名参数是否位于URL,是的话去掉并重定向,以隐藏URL中的用户名
                
                if (StringUtils.equals(request.getMethod(), "GET") && request.getQueryString().contains(userNameParameter)) {
                    response.sendRedirect(generateURIWithoutUsername(request));
                } else {
                    // 不是位于URL的话直接doFilter
                    filterChain.doFilter(request,response);
                }
            } else {
                // 用户名参数为空,直接doFilter
                filterChain.doFilter(request,response);
            }
        }
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
        }

        @Override
        public void destroy() {
        }

        // token有效性检验
        private boolean checkTokenValid(HttpServletRequest req, String token, String currentUserName) {

            try {
                // 当前登录用户和token对应的用户名不同,需要重新生成token
                if (!ComparatorUtils.equals(currentUserName, JwtUtils.parseJWT(token).getSubject())) {
                    FineLoggerFactory.getLogger().info("username changed:" + currentUserName);
                    return false;
                }
                Device device = NetworkHelper.getDevice(req);
                // 判断该token是否还保存在状态服务器中,也就是判断该token是否还有用
                LoginService.getInstance().loginStatusValid(token, TerminalHandler.getTerminal(req, device));
                return true;
            } catch (Exception e) {
            }
            return false;
        }

        // 去除URL参数中的用户名参数
        private String generateURIWithoutUsername(HttpServletRequest request) {

            List<String> queryParams = Arrays.asList(request.getQueryString().split("&"));
            if (!queryParams.isEmpty()) {
                StringBuilder queryStringWithoutUsername = new StringBuilder("?");
                for (String param : queryParams) {
                    if (!StringUtils.contains(param, userNameParameter)) {
                        queryStringWithoutUsername.append(param);
                        queryStringWithoutUsername.append("&");
                    }
                }
                String newUrl = queryStringWithoutUsername.toString();
                return request.getRequestURI() + newUrl.substring(0, newUrl.length()-1);
            } else {
                return request.getRequestURI();
            }
        }
    }

    注:如果遇到 IP 访问单点正常,域名访问立即提示登录信息失效,可能是因为 cookie 跨域了。映射的时候,域名跟 IP 不在同一个域,因为 cookie 是存在域下面的。这种场景,可以用 session 存放 Token。

    2.2.2 session

    package com.fr.io;

    import com.fr.data.NetworkHelper;
    import com.fr.decision.authority.data.User;
    import com.fr.decision.mobile.terminal.TerminalHandler;
    import com.fr.decision.webservice.exception.user.UserNotExistException;
    import com.fr.decision.webservice.utils.DecisionServiceConstants;
    import com.fr.decision.webservice.v10.login.LoginService;
    import com.fr.decision.webservice.v10.login.TokenResource;
    import com.fr.decision.webservice.v10.user.UserService;
    import com.fr.general.ComparatorUtils;
    import com.fr.log.FineLoggerFactory;
    import com.fr.security.JwtUtils;
    import com.fr.stable.StringUtils;
    import com.fr.stable.web.Device;

    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Arrays;
    import java.util.List;


    public class AuthFilter implements Filter {

        // 携带用户名的参数名称
        private static final String userNameParameter = "sysadmin";

        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

            HttpServletRequest request = (HttpServletRequest) servletRequest;
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            // 这个地方username的获取,根据具体你请求的时候把username放在哪了来确定
            //String username = request.getParameter(userNameParameter);
            String username = "sysadmin";
            FineLoggerFactory.getLogger().info("username="+username);
            // 用户名参数不为空时,走登录逻辑
            if (StringUtils.isNotEmpty(username)) {
                // 获取该用户名的token
             String oldToken = (String)request.getSession().getAttribute("fine_auth_token");
                FineLoggerFactory.getLogger().info("oldTokenSession=="+oldToken);
                System.out.println("oldtoken==="+oldToken);
                // 无token/token失效,则走登录逻辑
                if (StringUtils.isEmpty(oldToken) || !checkTokenValid(request, oldToken, username)) {
                    try {
                        // 系统中无该用户则抛出异常
                        User user = UserService.getInstance().getUserByUserName(username);
                        FineLoggerFactory.getLogger().info("user="+user);
                        System.out.println("user==="+user);
                        if (user == null) {
                            throw new UserNotExistException();
                        }
                        // 将token写入response
                        String token = LoginService.getInstance().login(request, response, username);
                        // 将token写入request
                        request.getSession().setAttribute("fine_auth_token", token);
                        //filterChain.doFilter(request,response);
                    } catch (Exception e) {
                        FineLoggerFactory.getLogger().error(e.getMessage(), e);
                    }
                }
                else {
                    // 用户名参数为空,直接doFilter
                    filterChain.doFilter(request,response);
                }
                
                // 检查用户名参数是否位于URL,是的话去掉并重定向,以隐藏URL中的用户名
                
                if (StringUtils.equals(request.getMethod(), "GET") && request.getQueryString().contains(userNameParameter)) {
                    response.sendRedirect(generateURIWithoutUsername(request));
                } else {
                    // 不是位于URL的话直接doFilter
                    filterChain.doFilter(request,response);
                }
            } else {
                // 用户名参数为空,直接doFilter
                filterChain.doFilter(request,response);
            }
        }
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
        }

        @Override
        public void destroy() {
        }

        // token有效性检验
        private boolean checkTokenValid(HttpServletRequest req, String token, String currentUserName) {

            try {
                // 当前登录用户和token对应的用户名不同,需要重新生成token
                if (!ComparatorUtils.equals(currentUserName, JwtUtils.parseJWT(token).getSubject())) {
                    FineLoggerFactory.getLogger().info("username changed:" + currentUserName);
                    return false;
                }
                Device device = NetworkHelper.getDevice(req);
                // 判断该token是否还保存在状态服务器中,也就是判断该token是否还有用
                LoginService.getInstance().loginStatusValid(token, TerminalHandler.getTerminal(req, device));
                return true;
            } catch (Exception e) {
            }
            return false;
        }

        // 去除URL参数中的用户名参数
        private String generateURIWithoutUsername(HttpServletRequest request) {

            List<String> queryParams = Arrays.asList(request.getQueryString().split("&"));
            if (!queryParams.isEmpty()) {
                StringBuilder queryStringWithoutUsername = new StringBuilder("?");
                for (String param : queryParams) {
                    if (!StringUtils.contains(param, userNameParameter)) {
                        queryStringWithoutUsername.append(param);
                        queryStringWithoutUsername.append("&");
                    }
                }
                String newUrl = queryStringWithoutUsername.toString();
                return request.getRequestURI() + newUrl.substring(0, newUrl.length()-1);
            } else {
                return request.getRequestURI();
            }
        }
    }

    2.3 编译 class 文件

    编译 Java 代码生成 class 文件,将文件放在%FR_HOME%\webapps\webroot\WEB-INF\classes\com\fr\io路径下,重启报表工程。

    注:class 文件放置路径与 Java 包名有关,根据实际修改即可。

    企业微信截图_15819206282641.png

    2.4 访问格式

    1)PC 端

    • 平台:http://ip:port/webroot/decision

    • 模板:http://ip:port/webroot/decision/view/report?viewlet=GettingStarted.cpt

    2)移动端

    • 平台:http://ip:port/webroot/decision/url/mobile

    •  模板:http://ip:port/webroot/decision/view/report?viewlet=GettingStarted.cpt&op=h5


    附件列表


    主题: 数据决策系统
    • 有帮助
    • 没帮助
    • 只是浏览
    • 评价文档,奖励 1 ~ 100 随机 F 豆!