實戰react技術棧+express前後端部落格專案(6)-- 使用session實現免登陸+管理後臺許可權驗證

Neal_yang發表於2017-10-13

專案地址:github.com/Nealyang/Re…

本想等專案做完再連載一波系列部落格,隨著開發的進行,也是的確遇到了不少坑,請教了不少人。遂想,何不一邊記錄踩坑,一邊分享收穫呢。分享當然是好的,
如果能做到集思廣益,那豈不是更美。我們的口號是:堅決不會爛尾

本部落格為連載程式碼部落格同步更新部落格,隨著專案往後開發可能會遇到前面寫的不合適的地方會再回頭修改。如有不妥~歡迎兄弟們不嗇賜教。謝謝!

session

後端部分

上一篇文章中,我們已經實現了前後端的登入功能。問題大家可能都已經發現了,當重新整理頁面的時候,之前登入過的現在得重新登入。顯然,這個並不是我們想想要的。

所以這裡我們採用session的機制來解決這類問題。不了session和coolie可以參考我這篇部落格

apiServer.js

app.use(cookieParser('express_react_cookie'));
app.use(session({
    secret:'express_react_cookie',
    resave: true,
    saveUninitialized:true,
    cookie: {maxAge: 60 * 1000 * 30}//過期時間
}));複製程式碼

因為是登入資訊,所以這裡我們採用的是session。首先需要在apiServer.js中引入cookie-parser和express-session中介軟體。

coolieParser裡面設定一個key,必須要和session中一致。然後設定coolie的過期時間。這裡我們設定為30min。

然後再使用者登入成功了以後,我們需要設定session

router.post('/login', (req, res) => {
    let {username, password} = req.body;
    if (!username) {
        responseClient(res, 400, 2, '使用者名稱不可為空');
        return;
    }
    if (!password) {
        responseClient(res, 400, 2, '密碼不可為空');
        return;
    }
    User.findOne({
        username,
        password: md5(password + MD5_SUFFIX)
    }).then(userInfo => {
        if (userInfo) {
            //登入成功
            let data = {};
            data.username = userInfo.username;
            data.userType = userInfo.type;
            data.userId = userInfo._id;
            //登入成功後設定session
            req.session.userInfo = data;

            responseClient(res, 200, 0, '登入成功', data);
            return;
        }
        responseClient(res, 400, 1, '使用者名稱密碼錯誤');

    }).catch(err => {
        responseClient(res);
    })
});複製程式碼

其中,
req.session.userInfo = data即為設定session的userInfo。

然後再server端需要另寫一個介面。在使用者開啟網站的時候就發起請求,驗證使用者是否已經登入。

//使用者驗證
router.get('/userInfo',function (req,res) {
    if(req.session.userInfo){
        responseClient(res,200,0,'',req.session.userInfo)
    }else{
        responseClient(res,200,1,'請重新登入',req.session.userInfo)
    }
});複製程式碼

很簡單,就是將請求中的req.session.userInfo的資訊返回過去。這樣,當使用者訪問網站的時候,先傳送這個請求,來判斷使用者知否已經登陸過。如果已經登陸過,拿到這個userInfo直接put一個action到reducer中,修改state狀態樹即可。

前端部分

前端部分比較常規。在最外層的container中,直接傳送請求即可

class AppIndex extends Component {

    constructor(props) {
        super(props);
        this.openNotification = this.openNotification.bind(this);
        this.shouldComponentUpdate = PureRenderMixiin.shouldComponentUpdate.bind(this);
    }

    openNotification(type, message) {
        let that = this;
        notification[type]({
            message: message,
            onClose: () => {
                that.props.clear_msg();
            }
        });
        that.props.clear_msg();
    };

    render() {
        let {isFetching} = this.props;
        return (
            <Router>
                <div>
                    <Switch>
                        <Route path='/404' component={NotFound}/>
                        <Route path='/admin' component={Admin}/>
                        <Route component={Front}/>
                    </Switch>
                    {isFetching && <Loading/>}
                    {this.props.notification && this.props.notification.content ?
                        (this.props.notification.type === 1 ?
                            this.openNotification('success', this.props.notification.content) :
                            this.openNotification('error', this.props.notification.content)) :
                        null}
                </div>
            </Router>
        )
    }

    componentDidMount() {
        this.props.user_auth();
    }

}複製程式碼

然後對應saga的處理也比較常規,這裡不再贅述。

許可權認證

因為是部落格系統,所以所謂的許可權就是判斷改登入使用者是否為管理員。我們在設計user表的時候,新增了身份一項。當然,我們可以隨意用別的字元來標識管理員和普通使用者。

 render() {
        const {url} = this.props.match;
        if(this.props.userInfo.userType){
            return (
                <div>
                    {
                        this.props.userInfo.userType === 'admin' ?
                            <div className={style.container}>
                                <div className={style.menuContainer}>
                                    <AdminMenu history={this.props.history}
                                               url={this.props.adminUrl}
                                               changeUrl={this.props.change_location_admin}/>
                                </div>
                                <div className={style.contentContainer}>
                                    <Switch>
                                        <Route exact path={url} component={AdminIndex}/>
                                        <Route path={`${url}/managerUser`} component={AdminManagerUser}/>
                                        <Route path={`${url}/managerTags`} component={AdminManagerTags}/>
                                        <Route path={`${url}/newArticle`} component={AdminNewArticle}/>
                                        <Route path={`${url}/detail`} component={Detail}/>
                                        <Route component={NotFound}/>
                                    </Switch>
                                </div>
                            </div> :
                            <Redirect to='/'/>
                    }
                </div>
            )
        }else{
            return <NotFound/>
        }
    }複製程式碼

在admin.js中,我們判斷state中是否有userInfo這個選項。


如果userInfo是有值的,那麼說明已經登入。如果沒有值,則跳轉到NotFound頁面。

為什麼先顯示notFound介面,而不是在userInfo為空的時候直接Redirect?

這裡有個大坑,具體看我segmentFault上的提問:react redux身份驗證,取state的問題

以上即為admin的許可權認證,如上,當admin登入到管理後天的時候,既可以到管理介面,當不是admin登入到管理後臺的時候,會直接Redirect到部落格首頁。

總結

如上,我們就直線了使用者的免登陸以及許可權管理的問題。主要就是通過session和狀態樹的判斷。
下一篇,我們就開始後端部分的開發~

專案實現步驟系列部落格


歡迎兄弟們加入:

Node.js技術交流群:209530601

React技術棧:398240621

前端技術雜談:604953717 (新建)


相關文章