关于登陆的配置问题总结

spring-servelet.xml

<?xml version="1.0" encoding="GBK"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cxf="http://cxf.apache.org/core"
    xmlns:p="http://cxf.apache.org/policy" xmlns:ss="http://www.springframework.org/schema/security"
    xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
    http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd 
    http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd 
    http://cxf.apache.org/policy http://cxf.apache.org/schemas/policy.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
    http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd 
    http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd 
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- 使用CGLIB自动创建代理Bean -->
    <aop:aspectj-autoproxy proxy-target-class="true">
    </aop:aspectj-autoproxy>

    <context:annotation-config />
    <context:component-scan base-package="com.suning.uras.admin.web" />

    <!-- 登陆权限插件包注解 -->
    <context:component-scan base-package="com.suning.uras.common" />

    <mvc:annotation-driven />

    <!-- mvc 登陆鉴权拦截器 -->
    <mvc:interceptors>
        <mvc:interceptor>
            <!-- 需要拦截的URL -->
            <mvc:mapping path="/*/**" />

            <bean class="com.suning.uras.common.interceptor.AuthLoginInterceptor">
                <!-- 登陆页面 -->
                <property name="loginUrl" value="/login.htm" />
                <!-- 放行URL配置 -->
                <property name="excludeList">
                    <list>
                        <value>/login.htm</value>
                        <value>/logout.htm</value>
                    </list>
                </property>
            </bean>
        </mvc:interceptor>
    </mvc:interceptors>

    <!--无权限异常处理页面 -->
    <bean id="exceptionResolver"
        class="com.suning.uras.common.exception.AuthRightFailedExceptionResolver"> 
        <!-- 
        class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        -->
        <property name="exceptionMappings">
            <props>
                <!-- 支持自定义异常跳转FTL页面或者响应JSON数据,格式要求:FTL页面以.ftl结尾,其他配置全部以JSON数据格式处理 -->
                <!-- JSON格式,根据实际无权限结果码配置,如果不配置,默认返回{"errorCode":"no_right","errorMessage":"无权限访问"} -->
                <!-- JSON格式数据支持JSONP,但是回调函数名称必须是callback-->
                <!-- JSON配置参考:

                 -->
                <prop key="com.suning.uras.common.exception.AuthRightFailedException">no_right.ftl</prop>
                <prop key="com.suning.uras.common.exception.AuthRightJsonFailedException">{"code":"1001","message":"no right message"}</prop>
            </props>
        </property>
        <property name="warnLogCategory" value="WARN"></property>
    </bean>



    <!--===================== view resovler ===================== -->
    <bean id="viewResolver" abstract="true">
        <property name="attributes">
            <props>
                <prop key="resRoot">@{resRoot}</prop>
                <prop key="envName">@{envName}</prop>
                <prop key="versionNo">@{appVersion}</prop>
                <prop key="esbUrl">$[esbUrl]</prop>
                <prop key="urasLoginUrl">$[uras.login.url]</prop>
            </props>
        </property>
    </bean>

    <!--freemarker页面解析器 -->
    <bean id="freemarkerResolver"
        class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"
        parent="viewResolver">
        <!--<property name="cache" value="true"/> -->
        <property name="order" value="1" />
        <property name="viewNames">
            <array>
                <value>*.ftl</value>
            </array>
        </property>
        <!-- <property name="suffix" value=".ftl" /> -->
        <property name="requestContextAttribute" value="request" />
        <property name="exposeSpringMacroHelpers" value="true" />
        <property name="exposeRequestAttributes" value="true" />
        <property name="exposeSessionAttributes" value="true" />
        <property name="allowSessionOverride" value="true" />
        <property name="contentType" value="text/html;charset=utf-8" /><!--编码 -->
        <property name="viewClass"
            value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" />
    </bean>
    <!-- ===================== view resolver end ====================== -->

    <!-- 文件上传支持 -->
    <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="utf-8"></property>
        <property name="maxUploadSize">
            <value>31457280</value><!-- 上传文件大小限制为30M,3*1024*1024 -->
        </property>
        <property name="maxInMemorySize">
            <value>4096</value>
        </property>
    </bean>

    <!-- 属性文件加载 -->
    <bean id="webPropertyConfig"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:conf/main-setting-web.properties</value>
            </list>
        </property>
        <property name="placeholderPrefix" value="@{" />
        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
    </bean>

    <!-- FreeMarker配置文件 -->
    <bean id="freemarkerConfig"
        class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
        <description>Required for Freemarker to work in web tier</description>
        <property name="configuration" ref="freemarkerConfiguration" />
    </bean>

    <!-- FreeMarker配置文件 -->
    <bean id="freemarkerConfiguration"
        class="org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean">
        <description>Using the Config directly so we can use it outside the
            web tier
        </description>
        <!-- 模板加载路径 -->
        <property name="templateLoaderPaths">
            <list>
                <value>/WEB-INF/freemarker/</value>
                <!-- <value>/WEB-INF/ftl_macro</value> -->
            </list>
        </property>
        <property name="configLocation">
            <value>classpath:conf/freemarker.properties</value>
        </property>
        <!--全局变量部分 -->
        <property name="freemarkerVariables">
            <map>
                <entry key="xml_escape" value-ref="fmXmlEscape" />
                <entry key="html_escape" value-ref="fmHtmlEscape" />
                <entry key="base" value="@{base}" />
                <entry key="envName" value="@{envName}" />
                <entry key="resRoot" value="@{resRoot}" />
                <entry key="esbUrl" value="$[esbUrl]" />
                <entry key="urasLoginUrl" value="$[uras.login.url]" />
                <entry key="loginDesKey" value="$[login.password.des.key]" />
            </map>
        </property>
        <property name="defaultEncoding" value="utf-8" />
    </bean>

    <!-- 针对xml文件里特殊字符转义 -->
    <bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape" />

    <!-- 针对html文件里特殊字符转义 -->
    <bean id="fmHtmlEscape" class="freemarker.template.utility.HtmlEscape" />

</beans>

拦截器的写法

/**
 * 登陆鉴权拦截器<br>
 * 〈功能详细描述〉
 * 
 * @author 15061841
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class AuthLoginInterceptor implements HandlerInterceptor {
    private static final Logger LOGGER = LoggerFactory.getLogger(AuthLoginInterceptor.class);

    private static final String DEFAULT_LOGIN_URL = "/login.ftl";

    /**
     * 拦截未登陆跳转登陆页URL
     */
    private String loginUrl;

    /**
     * 放行URL
     */
    private List<String> excludeList;

    @Autowired
    private AuthRightService authRightService;

    public String getLoginUrl() {
        return loginUrl;
    }

    public void setLoginUrl(String loginUrl) {
        this.loginUrl = loginUrl;
    }

    public List<String> getExcludeList() {
        return excludeList;
    }

    public void setExcludeList(List<String> excludeList) {
        this.excludeList = excludeList;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        LOGGER.info("AuthLoginInterceptor.preHandle enter.");
        // 校验放行URL
        String uri = request.getServletPath();
        if (!CollectionUtils.isEmpty(excludeList) && excludeList.contains(uri)) {
            return true;
        }
        // 请求参数
        String reqParam = request.getQueryString();
        if (StringUtils.isNotBlank(reqParam)) {
            uri += "?" + reqParam;
        }
        // 1、获取cookie中的loginToken
        String loginToken = "";
        Cookie[] cookies = request.getCookies();
        if (null != cookies && cookies.length > 0) {
            loginToken = getLoginTokenFromCookie(cookies);
        }
        // 2、RSF调用中台接口校验loginToken对应的session信息,返回对应userId
        String userId = authRightService.validateLoginSeesion(loginToken);

        // 设置默认登陆页面地址
        if (StringUtils.isBlank(loginUrl)) {
            loginUrl = DEFAULT_LOGIN_URL;
        }
        // 3、如果登陆session合法则放行,否则跳转登录页面重新登录
        boolean result = false;
        if (StringUtils.isBlank(userId)) {
            // 跳转登录页面
            response.sendRedirect(request.getContextPath() + loginUrl + "?targetUri=" + URLEncoder.encode(uri, "UTF-8"));
        } else {
            request.setAttribute("userId", userId);
            result = true;
        }
        return result;
    }

    /**
     * 功能描述: 获取登陆Token<br>
     * 〈功能详细描述〉
     *
     * @param loginToken
     * @param cookies
     * @return
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    private String getLoginTokenFromCookie(Cookie[] cookies) {
        String loginToken = "";
        for (Cookie cookie : cookies) {
            if ("loginToken".equals(cookie.getName())) {
                String cookieValue = cookie.getValue();
                String[] cookieValues = cookieValue.split("\\|");
                if (cookieValues.length > 1) {
                    loginToken = cookieValues[0];
                    break;
                }
            }
        }
        return loginToken;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        LOGGER.info("AuthLoginInterceptor.postHandle enter.");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        LOGGER.info("AuthLoginInterceptor.afterCompletion enter.");
    }

}

自定义登陆异常

/**
 * 自定义鉴权异常Resolver处理<br>
 * 〈功能详细描述〉
 * 
 * @author 15061841
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class AuthRightFailedExceptionResolver extends SimpleMappingExceptionResolver {
    private static final Logger logers = LoggerFactory.getLogger(AuthRightFailedExceptionResolver.class);

    private static final String ERROR_JSON = "{\"resultCode\":\"no_right\",\"resultMsg\":\"无权限访问\"}";

    private static final String LOGIN_FLAG_JSON_APPEND_BEGIN = "\"loginFlag\":\"1\",";

    private static final String CALLBACK_STR = "callback";

    @Override
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) {
        // response print json strings
        String viewName = determineViewName(ex, request);

        try {
            // 判断是否鉴权失败异常
            if (ex instanceof AuthRightFailedException) {
                // 如果是FTL页面提示错误
                Integer statusCode = determineStatusCode(request, viewName);
                logers.info("enter doResolveException() authRightFailedException,viewName={},statusCode={}", viewName,
                        statusCode);
                if (statusCode != null) {
                    applyStatusCodeIfPossible(request, response, statusCode);
                }
                if (StringUtils.isNotBlank(viewName) && viewName.endsWith(".ftl")) {
                    logers.info("doResolveException() authRightFailedException ready success!");
                    return getModelAndView(viewName, ex, request);
                }
            }
            if (ex instanceof AuthRightJsonFailedException) {
                logers.info("enter doResolveException() authRightJsonFailedException,viewName={}", viewName);
                PrintWriter out = response.getWriter();
                // 如果空并且是鉴权自定义异常 返回默认JSON格式
                if (StringUtils.isBlank(viewName)) {
                    viewName = ERROR_JSON;
                }
                // 处理未登录返回标识
                // 获取cookie中的loginToken,如果loginToken不存在则认为未登陆
                String loginToken = getLoginTokenFromCookie(request.getCookies());
                if ("null".equals(loginToken) || StringUtils.isBlank(loginToken)) {
                    response.addHeader("passport.login.flag", "1");
                    // 返回JSON串拼接未登录标识
                    String[] viewNames = viewName.split("\\{");
                    viewName = "{" + LOGIN_FLAG_JSON_APPEND_BEGIN + viewNames[1];
                }

                // 处理JSONP
                viewName = handleJsonp(request, viewName);

                logers.info("enter doResolveException() authRightJsonFailedException ready success,viewName={}",
                        viewName);
                // 设置ContentType
                response.setContentType("application/json");
                // 设置UTF-8避免乱码
                response.setCharacterEncoding("UTF-8");
                response.setHeader("Cache-Control", "no-cache, must-revalidate");
                out.print(viewName);
                out.close();

            }
            // 非鉴权失败异常 业务系统可自行定义Resolve处理
        } catch (Exception e) {
            logers.error("SimpleMappingExceptionJsonResolver.doResolveException() error", e);
        }
        return new ModelAndView();
    }

    /**
     * 功能描述: <br>
     * 〈功能详细描述〉
     * 
     * @param request
     * @param viewName
     * @return
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    private String handleJsonp(HttpServletRequest request, String viewName) {
        // 判断返回格式JSON还是JSONP
        // URL或者参数包含callback即认为是JSONP,和H5业务系统约定JSONP服务的回调方法名必须为callback,
        // java业务系统的JSON服务地址必须为xxx_callback开头.htm/do或xxx.htm/do?callback=callback
        String callbackMehodName = CALLBACK_STR;
        String reqURI = request.getRequestURI();
        String reqParam = request.getQueryString();
        if (StringUtils.isNotBlank(reqURI) && reqURI.contains("_callback")) {
            // 截取 _callback*到.do或.htm之间的字符串认为是JSONP回调函数的方法名
            int end = reqURI.indexOf(".do");
            if(end == -1) {
                end = reqURI.indexOf(".htm");
            }
            int begin = reqURI.indexOf("_callback");
            callbackMehodName = reqURI.substring(begin + 1, end);
            return callbackMehodName + "(" + viewName + ")";
        }

        if (StringUtils.isNotBlank(reqParam)
                && (reqParam.contains("callback=callback") || reqParam.contains(CALLBACK_STR))) {
            // 获取JSONP回调函数的方法名
            callbackMehodName = request.getParameter(CALLBACK_STR);
            return callbackMehodName + "(" + viewName + ")";
        }
        return viewName;
    }

    /**
     * 
     * 功能描述: 从cookie中获取loginToken<br>
     * 〈功能详细描述〉
     * 
     * @param cookies
     * @return
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    private String getLoginTokenFromCookie(Cookie[] cookies) {
        String loginTokenValue = "";
        if (null != cookies && cookies.length > 0) {
            for (Cookie c : cookies) {
                if ("loginToken".equals(c.getName())) {
                    loginTokenValue = c.getValue();
                    break;
                }
            }
        }
        // loginToken格式为token串|userId
        return loginTokenValue.split("\\|")[0];
    }

}

自定义异常

/**
 * 〈一句话功能简述〉<br>
 * 〈功能详细描述〉
 * 
 * @author 15061841
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class AuthRightFailedException extends RuntimeException {
    /**
     */
    private static final long serialVersionUID = 6533990418559037407L;

    public AuthRightFailedException() {
        // 添加自身构造器
    }

    public AuthRightFailedException(String message) {
        super(message);
    }

    public AuthRightFailedException(String message, Throwable cause) {
        super(message, cause);
    }

    public AuthRightFailedException(Throwable cause) {
        super(cause);
    }
}
AuthRightJsonFailedException
public class AuthRightJsonFailedException extends RuntimeException {
    /**
     */
    private static final long serialVersionUID = 6533990418559037407L;

    public AuthRightJsonFailedException() {
        super();
    }

    public AuthRightJsonFailedException(String message) {
        super(message);
    }

    public AuthRightJsonFailedException(String message, Throwable cause) {
        super(message, cause);
    }

    public AuthRightJsonFailedException(Throwable cause) {
        super(cause);
    }
}

登出功能 步骤 1.清理当前服务端的loginToken 并且 把Cookie值清空

 /**
     * 
     * 功能描述: 退出登录<br>
     * 〈功能详细描述〉
     * 
     * @param response
     * @param request
     * @param callback
     * @return
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    @RequestMapping("/logout_{callback}.do")
    public String logout(HttpServletResponse response, HttpServletRequest request,
            @PathVariable("callback") String callback) {
        // 获取cookie中loginToken
        String loginTokenValue = getLoginTokenFromCookie(request.getCookies());

        // 清理服务端的loginToken
        LoginResponse rsp = loginBusiness.logout(loginTokenValue);
        if (null != rsp && LOGIN_SUCCESS.equals(rsp.getResultCode())) {
            // 清除cookie信息
            // 设置登录的cookie空
            setCookie(null, response, null);
        }

        return ajaxJsonp(response, gson.toJson(rsp), callback);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值