1. 程式人生 > >後臺許可權管理專案總結

後臺許可權管理專案總結

        最近做了一個後臺的許可權管理專案,沒有用到springSecurity,也沒有用到shiro,純粹是用原生態的寫法做的,有點粗糙,但是思想沒變,這裡記錄一下自己的心得。

       首先是設計資料庫的表,一共5張表,分別為使用者表,角色表,許可權表,使用者角色關係表,角色許可權關係表。這裡遇到的最大的坑就一個,導致後臺程式被大改,這裡給自己警醒,場景是這樣的,當我手動從資料庫中刪除一條資料的時候,程式碼debug除錯的時候竟然查到我刪掉的資料,這是一件很詭異的事情,後來上網查了一些這方面的資料,雖然沒查到我這個問題的原因,但是解決方案算是找到了,即為:一張表除了有一個數據庫自帶的自增主鍵,還要設定一個邏輯主鍵,可以用UUID作為主鍵。第二個問題是專案中的刪除很少用到delete語句,一般都是軟刪除,即為新增一個欄位isDelete(0表示刪除,1表示存在),所以刪除即為更新一下這個欄位即可。

       然後是後臺程式方面:第一個肯定是登入操作,判斷邏輯還是有點繞的,首先根據使用者名稱查該使用者是否存在,如果不存在,即返回給前端錯誤碼和錯誤資訊;如果查到的話,再將查到的使用者的密碼和前臺傳過來的密碼進行比對,如果不等,那麼進行三次機會重新輸入,如果都輸入錯誤,則將該使用者的狀態更新為鎖定,表示該使用者暫時不能登入;如果該使用者密碼比對正確或者三次機會中有一次機會輸入正確,則表示該使用者登陸成功,更新該使用者資料庫密碼錯誤次數為初始值。然後用該使用者主鍵根據角色使用者關係表查詢該使用者的角色,為一個集合,再用該角色的主鍵根據角色許可權關係表查詢該角色的許可權資訊,為一個list,然後用該使用者的唯一標識,比如該使用者的編號,拼接一個隨機數,生成一個token,然後將該使用者資訊和許可權的list集合以及這個token封裝到一個物件中,返給前臺,還將這個資訊存在redis快取中,當然還有個自定義的本地快取,怎麼建立,這樣來:建立一個工具類,例如LocalCache類,然後在這個類中定義一個static的集合,例如:

                    private static List<快取儲存的物件> myList =  new ArrayList<>();

然後是使用者類和角色類的增刪改查,刪除資料改isDelete狀態,修改資料後返回修改後的資料資訊,這些沒什麼好說的,新增資料的時候要注意先查一下,如果資料庫中有這條資料的話,那麼不讓增加。程式碼需要try{}catch(){},這樣出現錯誤也能夠捕捉的到。區別許可權的選單級和按鈕級,這個很好區別,根據Controller的@RequestMapping("")中的path很好判斷。例如:

然後還有根據日期區間進行查詢,例如查詢當天的資料,例如查詢2018-12-12 00:00:00到2018-12-12 23:59:59這個日期區間的資料,但是前臺傳給你的只有2018-12-12日這個格式的資料,因此需要你進行轉換為你所需要的日期形式,如下:

package com.Jevin.controller;

import org.junit.Test;
import java.util.Calendar;
import java.util.Date;


public class DateUtil {

    /**
     * 獲取日期的00:00:00
     * @param startDate
     * @return
     */
    public static Date getStartTime(Date startDate){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate);
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        return calendar.getTime();
    }

    /**
     * 獲取日期的23:59:59
     * @param endDate
     * @return
     */
    public static Date getEndTime(Date endDate){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(endDate);
        calendar.set(Calendar.HOUR_OF_DAY,23);
        calendar.set(Calendar.MINUTE,59);
        calendar.set(Calendar.SECOND,59);
        return calendar.getTime();
    }

    @Test
    public void test(){
        System.out.println(getEndTime(new Date()));
    }

}

然後就是物件封裝的問題,即為同一個類,我們需要將其拆分為三個物件,一個用來接收前臺的引數,一個物件用來和資料庫進行互動,一個物件用來返回給前端。

然後是過濾器的問題,到目前為止我已經試過4中過濾器了:

第一種是springAOP過濾器:

package com.Jevin.controller;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;


public class PermissionInterceptor implements MethodInterceptor {
    
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("進入過濾器");
        return methodInvocation.proceed();
    }
}

配置檔案

<!-- 配置攔截器的bean -->
    <bean id="permissionInterceptor" class="com.Jevin.controller.PermissionInterceptor"/>
    <!-- springAOP方法攔截器配置 -->
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="beanNames">
            <list>
                <value>userController</value>
            </list>
        </property>
        <property name="interceptorNames">
            <list>
                <value>permissionInterceptor</value>
            </list>
        </property>
    </bean>
    <!-- 任意一個類的bean -->
    <bean id="userController" class="com.Jevin.controller.UserController"/>

第二種是jboss.resteasy中的CorsFilter

匯入一下依賴

<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-jaxrs</artifactId>
    <version>3.0.12.Final</version>
</dependency>
package com.Jevin.controller;

import org.jboss.resteasy.plugins.interceptors.CorsFilter;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.PreMatching;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import java.io.IOException;

@Provider
@PreMatching
public class PermissionFilter extends CorsFilter {

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {

        System.out.println("requestContext");
        boolean flag = false;
        if(!flag){
            Result result = new Result();
            result.setResponseCode("000");
            result.setReserveMsg("error message");

            Response.ResponseBuilder builder = Response.status(200).entity(result);
            builder.type(MediaType.APPLICATION_JSON);
            requestContext.abortWith(builder.build());
        }

    }
}

 

其中Result是一個結果集物件,主要用來返回給前端響應結果的。

第三種是javax.servlet.Filter中的doFilter()方法過濾器,

第四種是org.springframework.web.servlet.HandlerInterceptor,

這兩種比較常見,在網上隨處可以查到一大把,這裡就不說了。

然後是使用者狀態,比方說0表示正常,1表示銷戶,2表示鎖定,0,1,2是插入資料庫中的資料;正常,銷戶,鎖定是返回給前端的使用者狀態資訊,這裡最好用enum列舉型別來做,如下:

package com.Jevin.controller;

public enum UserStateEnum {

    NORMAL("0","正常"),
    CANCEL("1","登出"),
    LOCK("2","鎖定");

    private String code;
    private String status;

    UserStateEnum(String code,String status){
        this.code=code;
        this.status=status;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }
}

大致自己所走過的彎路,所總結的也就這些了,希望給道友一些友好的提示。。。