实战react技术栈+express前后端博客项目6-- 使用session实现免登陆+管理后台权限验证

项目地址:https://github.com/Nealyang/R...

本想等项目做完再连载一波系列博客,随着开发的进行,也是的确遇到了不少坑,请教了不少人。遂想,何不一边记录踩坑,一边分享收获呢。分享当然是好的,
如果能做到集思广益,那岂不是更美。我们的口号是:坚决不会烂尾

本博客为连载代码博客同步更新博客,随着项目往后开发可能会遇到前面写的不合适的地方会再回头修改。如有不妥~欢迎兄弟们不啬赐教。谢谢!

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,'密码不可为空');
        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,'登录成功',data);
            return;
        }
        responseClient(res,1,'用户名密码错误');

    }).catch(err => {
        responseClient(res);
    })
});

其中,
req.session.userInfo = data即为设置session的userInfo。

然后再server端需要另写一个接口。在用户打开网站的时候就发起请求,验证用户是否已经登录。

//用户验证
router.get('/userInfo',function (req,res) {
    if(req.session.userInfo){
        responseClient(res,'',req.session.userInfo)
    }else{
        responseClient(res,'请重新登录',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和状态树的判断。
下一篇,我们就开始后端部分的开发~

## 项目实现步骤系列博客

## 交流

倘若有哪里说的不是很明白,或者有什么需要与我交流,欢迎各位提issue。或者加群联系我~

扫码关注我的个人微信公众号,直接回复,必有回应。分享更多原创文章。点击交流学习加我微信、qq群。一起学习,一起进步

---

欢迎兄弟们加入:

Node.js技术交流群:209530601

React技术栈:398240621

前端技术杂谈:604953717 (新建)

---

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom