欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SpringBoot如何实现持久化登录状态获取

程序员文章站 2022-03-16 20:02:23
目录springboot 持久化登录状态获取1.编写登录的controller文件2.编写首页controller逻辑3.运行测试,成功springboot 实现登录登出,登录态管理1.设计表结构2....

springboot 持久化登录状态获取

1.编写登录的controller文件

写入cookie

//登陆成功后
//...将用户账号信息存入数据库中
//写cookie,(因存入数据库,无需写入session了)
            response.addcookie(new cookie("token",token));

2.编写首页controller逻辑

@controller
public class indexcontroller {
    @autowired
    private usermapper usermapper;
    @getmapping("/")
    public string index(httpservletrequest request){
        cookie[] cookies = request.getcookies();
        if (cookies != null){
            for (cookie cookie : cookies) {
                if (cookie.getname().equals("token")){
                    string token = cookie.getvalue();
                    system.out.println("准备进数据库");
                    user user = usermapper.findbytoken(token); //去数据库寻找该token值的用户信息
                    system.out.println(user.tostring());
                    if(user != null){ //若找到了这个用户信息
                        //写进session,让页面去展示
                        request.getsession().setattribute("user",user);
                    }
                    break;
                }
            }
        }
        return "index";
    }
}

3.运行测试,成功

springboot 实现登录登出,登录态管理

账户模块中必要的功能登录登出,相信这个大家都经常使用了。简单介绍下在springboot中的实现

先说下实现思路:

用户名密码存储在数据库中,前端发出请求,拦截器先检测用户有无登录,若有登录可直接请求接口。无需登录就可请求的接口需要加@nologin自定义注解。若未登录,前端跳转到登录页面,调用登录接口,系统在后台验证用户名密码,验证通过将用户信息存储在redis中和线程上下文中。

1.设计表结构

除了必要的用户名 密码 其他账户信息字段大家可根据自己系统需求添加。

create table `t_account` (
  `id` bigint(20) not null auto_increment comment '主键',
  `name` varchar(64) not null default '' comment '姓名',
  `mobile` varchar(32) not null comment '手机号',
  `identity` varchar(32) not null comment '身份证号码',
  `user_name` varchar(32) not null comment '账户',
  `password` varchar(64) not null default '' comment '登录密码',
  `accept_region` bigint(20) not null comment '受理中心(网点)编号',
  `status` int(11) not null default '1' comment '状态:  0 禁用,1 正常,9 删除',
  `create_time` timestamp not null default current_timestamp comment '创建时间',
  `create_by` bigint(20) default null comment '创建人id',
  `update_time` timestamp not null default current_timestamp on update current_timestamp comment '修改时间',
  `update_by` bigint(20) default null comment '修改人id',
  primary key (`id`)
) engine=innodb auto_increment=0 default charset=utf8 row_format=dynamic comment='c端网点人员账户表';

2.controller层

接收客户端传参,调用接口与数据库信息匹配,匹配成功返回用户信息。并且存储到redis中,且以当前回话sessionid为key,用户信息为value。

@restcontroller
@requestmapping(value = webconstants.web_prefix + "/account")
@api(tags = "account", description = "账户模块")
@noauth
public class accountcontroller { 
    @autowired
    private accountservice accountservice;
 
    @autowired
    private stringredistemplate redistemplate;
 
    @postmapping(value = "/login")
    @apioperation("登录")
    public responsevo<accountvo>login(@requestbody loginform form, httpservletrequest request,
                                      httpservletresponse response)   {
 
        httpsession session=request.getsession();
        accountdto accountdto=accountservice.login(form.getusername(),form.getpassword());
        if(null==accountdto){
            throw new bizexception("用户名或密码错误!");
        }
        redistemplate.opsforvalue().set(session.getid(), json.tojsonstring(accountdto));
        accountvo accountvo= beancopy.of(accountdto,new accountvo()).copy(beanutils::copyproperties).get();
        accountvo.setaceptregion(acceptregionenum.getdescbyvalue(accountdto.getaceptregion()));
        return responsevo.successresponse(accountvo);
    } 
 
    @login
    @postmapping(value = "/logout")
    @apioperation("登出")
    public responsevo logout(httpservletrequest request,httpservletresponse response){
        httpsession session=request.getsession();
        session.invalidate();
        redistemplate.delete(session.getid());
        return responsevo.successresponse();
    } 
}

3.创建请求拦截器

创建一个请求拦截器,用于检测用户登录态。通过session_id检测redis中有没有用户信息。如果存在则将用户信息存储当前线程上下文中(用户线程上下文实质就是基于hashmap的缓存),便于后续使用。这一步也可以放在登录成功后(这样也更严谨)。

@component
public class logininterceptor implements handlerinterceptor { 
    private logger logger= loggerfactory.getlogger(logininterceptor.class);
    @autowired
    private stringredistemplate redistemplate;
 
    @override
    public boolean prehandle(httpservletrequest request, httpservletresponse response, object handler) throws exception { 
        handlermethod handlermethod = (handlermethod) handler;
        class<?> clazz = handlermethod.getbeantype();
        method m = handlermethod.getmethod();
 
        //需登录才可以访问的(预约核验模块)
        if (clazz.isannotationpresent(nologin.class) || m.isannotationpresent(nologin.class)) {
            return true; 
        }
        httpsession session=request.getsession();
            //检测redis中是否含有sessionid
            string val=redistemplate.opsforvalue().get(session.getid());
            if(null!=val){
                logger.info(val);
                accountdto accountdto= json.parseobject(val,accountdto.class);
                acceptregionuservistor vistor=new acceptregionuservistor();
                beanutils.copyproperties(accountdto,vistor);
                acceptregionuserthreadcontext.putsessionvisitor(vistor);
                return true;
            }else{
                response.setstatus(401);
                throw  new bizexception("401","common.system.user.not.login");
            }        
    }
 
    @override
    public void posthandle(httpservletrequest request, httpservletresponse response, object handler, modelandview modelandview) throws exception { 
    } 
    @override
    public void aftercompletion(httpservletrequest request, httpservletresponse response, object handler, exception ex) throws exception { 
    }
} 

注册拦截器:(注册后的拦截器才会生效哦)

@configuration
public class webconfiguration extends webmvcconfigurationsupport {    
    @autowired
    private logininterceptor logininterceptor;      
    /**
     * 拦截器配置
     *
     * @param registry 注册类
     */
    @override
    public void addinterceptors(interceptorregistry registry) {        
        registry.addinterceptor(logininterceptor).addpathpatterns(webconstants.web_prefix + "/**"); 
        super.addinterceptors(registry);
    }
}

4.登出

获取到当前会话,清空回话信息,删除redis中对应sessionid的用户信息。代码见上第二段代码logout方法。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。