基於URL的權限管理(三)

思路:先創建一個專門的類ActiveUser用於存儲用戶登錄的信息,主要用於存儲用戶id,賬戶,名稱,菜單,權限。

認證攔截器主要是查看用戶是否已登陸,如果沒有轉發到登陸界面,用戶用賬戶跟密碼登錄時候先驗證賬戶密碼認證。

如果正確登陸之後進入授權攔截器中,授權攔截器主要查看session域中用戶的菜單與權限(如果其權限滿足能訪問資源就放行)。用戶每點一次按鈕都會訪問一個URL,都會進行權限的判斷。

在session中存取用戶信息的思路:根據用戶的id去關聯查詢用戶的菜單與權限以對象形式放入list中,並將查出來的信息存到ActiveUser,將ActiveUser存到session域中。菜單主要是進去之後左邊的大菜單,菜單的URL是點擊大菜單的時候跳轉的頁面,權限是其點擊小按鈕進行每一次訪問的URL(也會進行處理),這樣處理比較嚴謹。

 

 

 

1.流程

 

 

 

2.系統登陸

系統 登陸相當 於用戶身份認證,用戶成功,要在session中記錄用戶的身份信息.

 

操作流程:

         用戶進行登陸頁面

         輸入用戶名和密碼進行登陸

         進行用戶名和密碼校驗

         如果校驗通過,在session記錄用戶身份信息

 

   2.1    用戶的身份信息

創建專門類用於記錄用戶身份信息。

 

package cn.qlq.springmvc.pojo;


import java.util.Iterator;
import java.util.List;

import com.sun.org.apache.bcel.internal.generic.NEW;

/**
 * 用戶身份信息,存入session 由於tomcat將session會序列化在本地硬盤上,所以使用Serializable接口
 * 
 * @author Thinkpad
 * 
 */
public class ActiveUser implements java.io.Serializable {
    private String userid;//用戶id(主鍵)
    private String usercode;// 用戶賬號
    private String username;// 用戶名稱

    private List<SysPermission> menus;// 菜單
    private List<SysPermission> permissions;// 權限

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }


    public String getUsercode() {
        return usercode;
    }

    public void setUsercode(String usercode) {
        this.usercode = usercode;
    }

    public String getUserid() {
        return userid;
    }

    public void setUserid(String userid) {
        this.userid = userid;
    }

    public List<SysPermission> getMenus() {
        return menus;
    }

    public void setMenus(List<SysPermission> menus) {
        this.menus = menus;
    }

    public List<SysPermission> getPermissions() {
        return permissions;
    }

    public void setPermissions(List<SysPermission> permissions) {
        this.permissions = permissions;
    }

    
}

 

 

2.2             mapper

mapper接口: 根據用戶賬號查詢用戶(sys_user)信息(使用逆向工程生成的mapper)

查詢菜單與權限的時候需要進行多表查詢,自定義mapper

 

mapper.java

 

public interface SysPermissionMapperCustom {
    
    //根據用戶id查詢菜單
    public List<SysPermission> findMenuListByUserId(String userid)throws Exception;
    //根據用戶id查詢權限url
    public List<SysPermission> findPermissionListByUserId(String userid)throws Exception;

}

 

 

mapper.xml

 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="cn.qlq.springmvc.mapper.SysPermissionMapperCustom" >
  
  
  <!-- 根據用戶id查詢url -->
  <select id="findPermissionListByUserId" parameterType="string" resultType="cn.qlq.springmvc.pojo.SysPermission">
      SELECT 
      * 
    FROM
      sys_permission 
    WHERE TYPE = 'permission' 
      AND id IN 
      (SELECT 
        sys_permission_id 
      FROM
        sys_role_permission 
      WHERE sys_role_id IN 
        (SELECT 
          sys_role_id 
        FROM
          sys_user_role 
        WHERE sys_user_id = #{id}))
  </select>
  
   <!-- 根據用戶id查詢菜單 -->
  <select id="findMenuListByUserId"  parameterType="string" resultType="cn.qlq.springmvc.pojo.SysPermission">
          SELECT 
      * 
    FROM
      sys_permission 
    WHERE TYPE = 'menu' 
      AND id IN 
      (SELECT 
        sys_permission_id 
      FROM
        sys_role_permission 
      WHERE sys_role_id IN 
        (SELECT 
          sys_role_id 
        FROM
          sys_user_role 
        WHERE sys_user_id = #{id}))
  </select>
  
</mapper>

 

 

 

 

2.3 Service(進行用戶名和密碼校驗)

 

接口功能:根據用戶的身份和密碼 進行認證,如果認證通過,返回用戶身份信息

認證過程:

         根據用戶身份(賬號)查詢數據庫,如果查詢不到用戶不存在

         對輸入的密碼 和數據庫密碼 進行比對,如果一致,認證通過

 

package cn.qlq.springmvc.serviceImpl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.qlq.springmvc.Exception.MyException;
import cn.qlq.springmvc.mapper.SysPermissionMapperCustom;
import cn.qlq.springmvc.mapper.SysUserMapper;
import cn.qlq.springmvc.pojo.ActiveUser;
import cn.qlq.springmvc.pojo.SysPermission;
import cn.qlq.springmvc.pojo.SysUser;
import cn.qlq.springmvc.pojo.SysUserExample;
import cn.qlq.springmvc.service.SysService;
import cn.qlq.springmvc.utils.MD5;

/**
 * 認證和授權
 * 
 * @author: qlq
 * @date : 2017年7月28日上午10:45:52
 */
@Service
public class SysServiceImpl implements SysService {

    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private SysPermissionMapperCustom sysPermissionMapperCustom;

    @Override
    public ActiveUser authenticat(String userCode, String password) throws Exception {
        /**
         * 認證過程: 根據用戶身份(賬號)查詢數據庫,如果查詢不到用戶不存在 對輸入的密碼 和數據庫密碼 進行比對,如果一致,認證通過
         */
        // 根據用戶賬號查詢數據庫
        SysUser sysUser = this.findSysUserByUserCode(userCode);

        if (sysUser == null) {
            // 拋出異常
            throw new MyException("用戶賬號不存在");
        }

        // 數據庫密碼 (md5密碼 )
        String password_db = sysUser.getPassword();

        // 對輸入的密碼 和數據庫密碼 進行比對,如果一致,認證通過
        // 對頁面輸入的密碼 進行md5加密
        String password_input_md5 = new MD5().getMD5ofStr(password);
        if (!password_input_md5.equalsIgnoreCase(password_db)) {
            // 拋出異常
            throw new MyException("用戶名或密碼 錯誤");
        }
        // 得到用戶id
        String userid = sysUser.getId();
        // 根據用戶id查詢菜單
        List<SysPermission> menus = this.findMenuListByUserId(userid);

        // 根據用戶id查詢權限url
        List<SysPermission> permissions = this.findPermissionListByUserId(userid);

        // 認證通過,返回用戶身份信息
        ActiveUser activeUser = new ActiveUser();
        activeUser.setUserid(sysUser.getId());
        activeUser.setUsercode(userCode);
        activeUser.setUsername(sysUser.getUsername());// 用戶名稱

        // 放入權限範圍的菜單和url
        activeUser.setMenus(menus);
        activeUser.setPermissions(permissions);

        return activeUser;
    }

    // 根據用戶賬號查詢用戶信息
    public SysUser findSysUserByUserCode(String userCode) throws Exception {
        // 根據用戶名查詢用戶信息
        SysUserExample sysUserExample = new SysUserExample();
        SysUserExample.Criteria criteria = sysUserExample.createCriteria();
        criteria.andUsercodeEqualTo(userCode);

        List<SysUser> list = sysUserMapper.selectByExample(sysUserExample);

        if (list != null && list.size() == 1) {
            return list.get(0);
        }

        return null;
    }

    @Override
    public List<SysPermission> findMenuListByUserId(String userid) throws Exception {

        return sysPermissionMapperCustom.findMenuListByUserId(userid);
    }

    @Override
    public List<SysPermission> findPermissionListByUserId(String userid) throws Exception {

        return sysPermissionMapperCustom.findPermissionListByUserId(userid);
    }
}

 

 

 

2.4      controller(記錄session)

 

package cn.qlq.springmvc.controller;


import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import cn.qlq.springmvc.Exception.MyException;
import cn.qlq.springmvc.pojo.ActiveUser;
import cn.qlq.springmvc.service.SysService;

@Controller
public class LoginController {
    
    @Autowired
    private SysService sysService;
    
    
    //用戶登陸提交方法
    /**
     * 
     * <p>Title: login</p>
     * <p>Description: </p>
     * @param session
     * @param randomcode 輸入的驗證碼
     * @param usercode 用戶賬號
     * @param password 用戶密碼 
     * @return
     * @throws Exception
     */
    @RequestMapping("/login")
    public String login(HttpSession session, String randomcode,String usercode,String password)throws Exception{
        
        //校驗驗證碼,防止惡性攻擊
        //從session獲取正確驗證碼
        String validateCode = (String) session.getAttribute("validateCode");
        
        //輸入的驗證和session中的驗證進行對比 
        if(!randomcode.equals(validateCode)){
            //拋出異常
            throw new MyException("驗證碼輸入錯誤");
        }
        
        //調用service校驗用戶賬號和密碼的正確性
        ActiveUser activeUser = sysService.authenticat(usercode, password);
        
        //如果service校驗通過,將用戶身份記錄到session
        session.setAttribute("activeUser", activeUser);
        //重定向到商品查詢頁面
        return "redirect:/first.action";
    }
    
    //用戶退出
    @RequestMapping("/logout")
    public String logout(HttpSession session)throws Exception{
        
        //session失效
        session.invalidate();
        //重定向到商品查詢頁面
        return "redirect:/first.action";
        
    }
    

}

 

 

 

 

 

2.5     用戶認證攔截器

package cn.qlq.springmvc.inteceptor;

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

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
 * SpringMVC的攔截器
* @author: qlq
* @date :  2017年7月22日下午12:20:52
 */
public class Inteceptor1 implements HandlerInterceptor{


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {
//        判斷是否是登陸
        String requestURI = request.getRequestURI();  //springmvc-mybatis/itemlist.action
        StringBuffer requestURL = request.getRequestURL(); //http://localhost:8080/springmvc-mybatis/itemlist.action
//        判斷用戶是否登陸  如果沒有登陸  重定向到登陸頁面   不放行   如果登陸了  就放行了
        if(!requestURI.contains("login")){
            Object attribute = request.getSession().getAttribute("user");
            if(attribute==null){
                response.sendRedirect(request.getContextPath()+"/login.action");
                return false;
            }
        }
        //不放行的話返回false
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
            throws Exception {
        System.out.println("這是方法後1");        
    }
    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
        // TODO Auto-generated method stub
        System.out.println("這是頁面渲染後1");
    }



    
}

 

 2.6用戶授權攔截器(在認證攔截器之後配置)

 

package cn.qlq.springmvc.inteceptor;



import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import cn.qlq.springmvc.pojo.ActiveUser;
import cn.qlq.springmvc.pojo.SysPermission;
import cn.qlq.springmvc.utils.ResourcesUtil;



public class PermissionInterceptor implements HandlerInterceptor {

    //在執行handler之前來執行的
    //用於用戶認證校驗、用戶權限校驗
    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        
        //得到請求的url
        String url = request.getRequestURI();
        
        //判斷是否是公開 地址
        //實際開發中需要公開 地址配置在配置文件中
        //從配置中取逆名訪問url
        
        List<String> open_urls = ResourcesUtil.gekeyList("anonymousURL");
        //遍歷公開 地址,如果是公開 地址則放行
        for(String open_url:open_urls){
            if(url.indexOf(open_url)>=0){
                //如果是公開 地址則放行
                return true;
            }
        }
        
        //從配置文件中獲取公共訪問地址
        List<String> common_urls = ResourcesUtil.gekeyList("commonURL");
        //遍歷公用 地址,如果是公用 地址則放行
        for(String common_url:common_urls){
            if(url.indexOf(common_url)>=0){
                //如果是公開 地址則放行
                return true;
            }
        }
        
        //獲取session
        HttpSession session = request.getSession();
        ActiveUser activeUser = (ActiveUser) session.getAttribute("activeUser");
        //從session中取權限範圍的url
        List<SysPermission> permissions = activeUser.getPermissions();
        for(SysPermission sysPermission:permissions){
            //權限的url
            String permission_url = sysPermission.getUrl();
            if(url.indexOf(permission_url)>=0){
                //如果是權限的url 地址則放行
                return true;
            }
        }
        
        //執行到這裏攔截,跳轉到無權訪問的提示頁面
        request.getRequestDispatcher("/WEB-INF/jsp/refuse.jsp").forward(request, response);
        
        //如果返回false表示攔截不繼續執行handler,如果返回true表示放行
        return false;
    }
    //在執行handler返回modelAndView之前來執行
    //如果需要向頁面提供一些公用 的數據或配置一些視圖信息,使用此方法實現 從modelAndView入手
    @Override
    public void postHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("HandlerInterceptor1...postHandle");
        
    }
    //執行handler之後執行此方法
    //作系統 統一異常處理,進行方法執行性能監控,在preHandle中設置一個時間點,在afterCompletion設置一個時間,兩個時間點的差就是執行時長
    //實現 系統 統一日誌記錄
    @Override
    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("HandlerInterceptor1...afterCompletion");
    }

}

 

源碼地址:https://github.com/qiao-zhi/quanxian.git

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章