SpringBoot如何实现持久化登录状态获取
目录
- SpringBoot 持久化登录状态获取
- 1.编写登录的controller文件
- 2.编写首页Controller逻辑
- 3.运行测试,成功
- SpringBoot 实现登录登出,登录态管理
- 1.设计表结构
- 2.controller层
- 3.创建请求拦截器
- 4.登出
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方法。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持自由互联。
【本文由http://www.1234xp.com/xgzq.html首发,转载请保留出处,谢谢】