基于session做的权限控制

Posted aigeileshei

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于session做的权限控制相关的知识,希望对你有一定的参考价值。

一直听说做权限将登陆信息放在session中,实际也说不太出个所以然来,幸运在工作当中接触到了对应的代码的copy。

实现思路:

  类似于粗粒度的权限控制

  将权限控制的文件按包分隔好,对应的url前缀也遵照一些标准统一。

  定义包装用户信息类,包括登录后的用户信息和登录状态,用户授权信息等

  使用过滤器,拦截通用请求、登录请求之外的所有请求。

    过滤器中进行session中包装用户信息类是否存在,是否登录,如果有且有效则跳转对应页面,无则跳转登录页面

  登录完成在session中写入用户的具体信息,包括登录状况和授权信息。

  权限菜单的控制体现在入口,入口在前端显示的可操作菜单中只会有用户被授权的部分。利用z-tree类似组件取得用户权限和所有菜单的交集。

 

技术分享图片
package com.kunpu.appopiqc.web.filter;

import java.io.IOException;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import com.kunpu.appopiqc.web.util.Constant;


/**
 * Servlet Filter implementation class LoginFilter
 */
public class LoginFilter implements Filter {

  public FilterConfig config;

  /**
   * Default constructor.
   */
  public LoginFilter() {
    // TODO Auto-generated constructor stub
  }

  public static boolean isContains(String container, String[] regx) {
    boolean result = false;

    for (int i = 0; i < regx.length; i++) {
      if (container.indexOf(regx[i]) != -1) {
        return true;
      }
    }
    return result;
  }

  /**
   * @see Filter#destroy()
   */
  public void destroy() {
    config = null;
  }

  /**
   * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
   */
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    HttpServletRequest hrequest = (HttpServletRequest) request;
    HttpServletResponseWrapper wrapper =
        new HttpServletResponseWrapper((HttpServletResponse) response);

    String logonStrings = config.getInitParameter("logonStrings"); // 登录登陆页面
    String includeStrings = config.getInitParameter("includeStrings"); // 过滤资源后缀参数
    String redirectPath = hrequest.getContextPath() + config.getInitParameter("redirectPath");// 没有登陆转向页面
    String disabletestfilter = config.getInitParameter("disabletestfilter");// 过滤器是否有效

    if (disabletestfilter.toUpperCase().equals("Y")) { // 过滤无效
      chain.doFilter(request, response);
      return;
    }
    String[] logonList = logonStrings.split(";");
    String[] includeList = includeStrings.split(";");

    // 只对指定过滤参数后缀进行过滤
    if (!this.isContains(hrequest.getRequestURI(), includeList)) {
      chain.doFilter(request, response);
      return;
    }

    // 对登录页面不进行过滤
    if (this.isContains(hrequest.getRequestURI(), logonList)) {
      chain.doFilter(request, response);
      return;
    }

    // 判断用户是否登录
    String user = (String) hrequest.getSession().getAttribute(Constant.UserOnly);
    if (user == null) {
      wrapper.sendRedirect(redirectPath);
      return;
    } else {
      chain.doFilter(request, response);
      return;
    }
  }

  /**
   * @see Filter#init(FilterConfig)
   */
  public void init(FilterConfig filterConfig) throws ServletException {
    config = filterConfig;
  }
}
loginFilter
技术分享图片
   <filter>
        <filter-name>SessionFilter</filter-name>
        <filter-class>com.kunpu.appopiqc.web.filter.LoginFilter</filter-class>
        <!-- 对登录页面不进行过滤 -->
        <init-param>
            <param-name>logonStrings</param-name>
            <param-value>/common/;/login/</param-value>
        </init-param>
        <!-- 只对指定过滤参数后缀进行过滤 -->
        <init-param>
            <param-name>includeStrings</param-name>
            <param-value>/admin/;/collect/</param-value>
        </init-param>
        <!-- 未通过跳转到登录界面 -->
        <init-param>
            <param-name>redirectPath</param-name>
            <param-value>/index.jsp</param-value>
        </init-param>
        <!-- Y:过滤无效 -->
        <init-param>
            <param-name>disabletestfilter</param-name>
            <param-value>N</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>SessionFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <session-config>
        <session-timeout>60</session-timeout>
    </session-config>
web.xml
技术分享图片
@RequestMapping(value = "/common/doLogin", method = RequestMethod.POST, consumes = {
      "application/json;charset=UTF-8"})
  @ResponseBody
  public AccountLoginResponse doLogin(HttpServletRequest request, HttpServletResponse response,
      @RequestBody AccountLoginRequest accountRequest) throws Exception {
    AccountLoginResponse login = new AccountLoginResponse();

    // 1.执行登录操作
    try {
      AccountLoginRequest req = new AccountLoginRequest();
      req.setSysId(APPCodeEnum.KPBP_APPOPIQC.sysId);
      req.setReqSerial(UUID.randomUUID().toString());
      req.setInstitutionCode(accountRequest.getInstitutionCode());
      req.setAccountCode(accountRequest.getAccountCode());
      req.setAccountPassword(accountRequest.getAccountPassword());
      login = accountFacade.login(req);

      LOGGER.error("登录结果{}", ToStringBuilder.reflectionToString(login),
          ToStringStyle.SHORT_PREFIX_STYLE);
      if (login != null && AppopiqcRespCode.RESP_000000.getCode().equals(login.getRespCode())) {
        request.getSession().setAttribute(Constant.LoginUser, login);
        request.getSession().setAttribute(Constant.UserOnly, "true");
        return login;
      }

    } catch (Exception e) {
      LOGGER.error("", e);
    }

    // 2.显示错误信息
    login = new AccountLoginResponse();
    login.setMemo("账号/密码错误");
    request.getSession().setAttribute(Constant.LoginUser, null);
    request.getSession().setAttribute(Constant.UserOnly, null);
    return login;

  }
登录代码
技术分享图片
@RequestMapping(value = "/admin/center")
  public ModelAndView center(HttpServletRequest request, HttpServletResponse response)
      throws Exception {
    ModelAndView mv = new ModelAndView();
    AccountLoginResponse accountLoginResponse = null;
    try {
      accountLoginResponse =
          (AccountLoginResponse) request.getSession().getAttribute(Constant.LoginUser);

    } catch (Exception e) {
      request.setAttribute("retCode", CommonEnums.NOT_SESSION.getCode());
    }
    QueryMenuRequest req = new QueryMenuRequest();
    req.setSysId(APPCodeEnum.KPBP_APPOPIQC.sysId);
    req.setReqSerial(UUID.randomUUID().toString());
    QueryMenuResponse resp = menuFacade.queryMenuList(req);
    LOGGER.debug("用户菜单{}", ToStringBuilder.reflectionToString(resp),
        ToStringStyle.SHORT_PREFIX_STYLE);

    List<MenuBean> menus = resp == null ? new ArrayList() : resp.getMenuBeanList();
    String isLeader = accountLoginResponse.getIsLeader();
    if (menus != null && !menus.isEmpty()) {
      for (int i = 0; i < menus.size(); i++) {
        // 针对菜单特殊处理,暂时没有
      }
    }
    mv.addObject("menus", menus);
    mv.setViewName("center");
    return mv;
  }
菜单展示代码
技术分享图片
<!--正常菜单--> 
            <div class="theme-left-normal">
                <!--theme-left-switch 如果不需要缩进按钮,删除该对象即可-->
                <div class="left-control-switch theme-left-switch"><i
                        class="fa fa-chevron-left fa-lg"></i></div>

                <!--start class="easyui-layout"-->
                <div class="easyui-layout" data-options="border:false,fit:true">
                    <!--start region:north-->
                    <div data-options="region:‘north‘,border:false" style="height:100px;">
                        <!--start theme-left-user-panel-->
                        <div class="theme-left-user-panel">
                        </div>
                        <!--end theme-left-user-panel-->
                    </div>
                    <!--end region:north-->

                    <!--start region:center-->
                    <div data-options="region:‘center‘,border:false">

                        <!--start easyui-accordion-->
                        <div class="easyui-accordion" data-options="border:false,fit:true">
                        <#if menus?? >
                          <#list menus as menu>
                              <#if (menu.menuType!‘‘) == ‘DESKTOP_MENU‘ && (menu.parentCode!‘‘) == ‘‘>
                            <div title="${menu.menuName!}">
                                <ul class="easyui-datalist" data-options="border:false,fit:true">
                                   <#list menus as menu2>
                                   <#if menu2.parentCode! == menu.menuCode>
                                      <li>
                                          <a onclick="openHref(‘${menu2.menuCode}‘,‘${menu2.menuName!}‘,‘${menu2.menuUrl!}‘)"
                                             target="mainFrame"
                                             style="cursor:pointer;">${menu2.menuName!}</a></li>
                                   </#if>
                                   </#list>
                                </ul>
                            </div>
                              </#if>
                          </#list>
                        </#if>

                        </div>
                        <!--end easyui-accordion-->

                    </div>
                    <!--end region:center-->
                </div>
                <!--end class="easyui-layout"-->

            </div>
            <!--最小化菜单-->
            <div class="theme-left-minimal">
                <ul class="easyui-datalist" data-options="border:false,fit:true">
                   <#if menus??>
                       <#list menus as menu>
                           <#if (menu.menuType!‘‘) == ‘DESKTOP_MENU‘ && (menu.parentCode!‘‘) == ‘‘>
                               <#list menus as menu2>
                                   <#if menu2.parentCode! == menu.menuCode >
                                   <li>
                                       <a onclick="openHref(‘${menu2.menuCode}‘,‘${menu2.menuName!}‘,‘${menu2.menuUrl!}‘)"
                                          style="cursor:pointer;"><i class="fa fa-home fa-2x"></i>
                                           <p>${menu2.menuName!}</p></a></li>
                                       <#break>
                                   </#if>
                               </#list>
                           </#if>
                       </#list>
                   </#if>
                    <li><a class="left-control-switch"><i class="fa fa-chevron-right fa-2x"></i>
                        <p>打开</p></a></li>
                </ul>
            </div>
菜单代码的页面
技术分享图片
  @RequestMapping(value = "/account/toLogout")
  public ModelAndView toLogout(HttpServletRequest request) throws Exception {
    ModelAndView mv = new ModelAndView();
    mv.setViewName("account/login");
    request.getSession().setAttribute(Constant.LoginUser, null);
    request.getSession().setAttribute(Constant.UserOnly, null);
    return mv;

  }

  @RequestMapping(value = "/account/doModifyPasswd", method = RequestMethod.POST)
  @ResponseBody
  public Result<Void> doModifyPasswd(HttpServletRequest request,
      @RequestParam("oldPasswd") String oldPasswd, @RequestParam("newPasswd") String newPasswd,
      @RequestParam("repleatPasswd") String repleatPasswd) throws Exception {
    String msg = "";
    String errorCode = "-1";

    Result<Void> rs = new Result<Void>();
    rs.setCode(errorCode);
    AccountLoginRequest loginReq = new AccountLoginRequest();


    AccountLoginResponse login =
        (AccountLoginResponse) request.getSession().getAttribute(Constant.LoginUser);
    if (login == null) {
      msg = "用户还未登录.";
      rs.setCode(errorCode);
      rs.setMsg(msg);
      return rs;
    }

    loginReq.setInstitutionCode(login.getInstitutionCode());
    loginReq.setAccountCode(login.getAccountCode());
    loginReq.setAccountPassword(oldPasswd);
    loginReq.setSysId(APPCodeEnum.KPBP_APPOPIQC.sysId);
    loginReq.setReqSerial(UUID.randomUUID().toString());
    // 校验原密码
    AccountLoginResponse checkOldPwd = accountFacade.login(loginReq);
    if (StringUtils.isNotEmpty(checkOldPwd.getRespCode())
        && !checkOldPwd.getRespCode().equals(AppopiqcRespCode.RESP_000000.getCode())) {
      msg = "旧密码不正确.";
      rs.setCode(errorCode);
      rs.setMsg(msg);
      return rs;
    }


    if (StringUtils.isNotBlank(newPasswd) && !newPasswd.equals(repleatPasswd)) {
      msg = "两次输入的密码不一致.";
      rs.setCode(errorCode);
      rs.setMsg(msg);
      return rs;

    }

    AccountChangePasswordRequest changePasswordReq = new AccountChangePasswordRequest();
    changePasswordReq.setInstitutionCode(login.getInstitutionCode());
    changePasswordReq.setAccountCode(login.getAccountCode());
    // 修改用户密码
    changePasswordReq.setAccountPassword(newPasswd);
    changePasswordReq.setSysId(APPCodeEnum.KPBP_APPOPIQC.sysId);
    changePasswordReq.setReqSerial(UUID.randomUUID().toString());

    try {
      AccountChangePasswordResponse account = accountFacade.changePassword(changePasswordReq);
      LOGGER.debug("修改结果{}", ToStringBuilder.reflectionToString(account),
          ToStringStyle.SHORT_PREFIX_STYLE);

      if (account != null && AppopiqcRespCode.RESP_000000.getCode().equals(account.getRespCode())) {
        rs.setCode("1");
        rs.setMsg("修改用户密码成功");
        return rs;
      }
      errorCode = (account == null) ? "-1" : account.getRespCode();

    } catch (Exception e) {
      LOGGER.error("", e);
    }
    rs.setCode(errorCode);
    rs.setMsg("修改用户密码失败");
    return rs;

  }

  @RequestMapping(value = "/account/toModifyPassword")
  public ModelAndView toModifyPasswd(HttpServletRequest request) {
    ModelAndView mv = new ModelAndView();
    mv.setViewName("/account/password");
    request.getSession().setAttribute(Constant.UserOnly, null);
    return mv;
  }

  @RequestMapping(value = "/account/info")
  @ResponseBody
  public AccountLoginResponse userInfo(HttpServletRequest request) {
    AccountLoginResponse login =
        (AccountLoginResponse) request.getSession().getAttribute(Constant.LoginUser);
    return login;
  }
注销改密查用户信息等

 

例子链接:https://pan.baidu.com/s/1BvLleNnIyvoy-AeRobZM-g

 

以上是关于基于session做的权限控制的主要内容,如果未能解决你的问题,请参考以下文章

spring session 和 spring security整合

JAVA WEB 中登录的session的判断 如何控制用户权限可以访问那些东西

rbac基于角色的权限控制组件目录

分布式WebSocket - 5SprintBoot集成STOMP协议,session权限管理

权限管理系统

AngularJS中实现权限控制 - 基于RBAC