php拦截器 前后端分离,一看就懂!基于Springboot 拦截器的前后端分离式登录拦截...

本文介绍了一种使用Spring原生技术实现登录拦截的方法,避免了在小型系统中使用Shiro的复杂性。通过生成和验证token来管理用户会话,实现了前后端分离的登录验证。在拦截器中,检查token的有效性和用户信息,当token过期或无效时返回错误信息。项目源码已上传至GitHub,可供参考。此外,文章还提及此方法同样适用于权限拦截,只需添加额外的拦截器进行权限验证。
摘要由CSDN通过智能技术生成

之前写过一篇关于Springboot+Shiro实现前后端分离的权限管理系统。但是由于使用了框架,对于一些小系统,实在用不上Shiro,而且还要加上学习成本。今天就来用原生的Spring技术实现登录拦截。

前后端分离

要实现前后端分离,需要考虑以下2个问题: 1. 项目不再基于session了,如何知道访问者是谁? 2. 如何确认访问者的权限?

前后端分离,一般都是通过token实现,本项目也是一样;用户登录时,生成token及 token过期时间,token与用户是一一对应关系,调用接口的时候,把token放到header或 请求参数中,服务端就知道是谁在调用接口。

源码先双手奉上:https://github.com/FENGZHIJIE1998/Auth-demo

各位客官觉得好用记得给个Star!

项目架构图

导包、配置文件都省略。

第一步编写自己的拦截器AuthInteceptor

public class AuthInterceptor implements HandlerInterceptor {

@Autowired

private AuthService authService;

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {

String token = TokenUtil.getRequestToken(request);

//如果token为空

if (StringUtils.isBlank(token)) {

setReturn(response,400,"用户未登录,请先登录");

return false;

}

//1. 根据token,查询用户信息

UserEntity userEntity = authService.findByToken(token);

//2. 若用户不存在,

if (userEntity == null) {

setReturn(response,400,"用户不存在");

return false;

}

//3. token失效

if (userEntity.getExpireTime().isBefore(LocalDateTime.now())) {

setReturn(response,400,"用户登录凭证已失效,请重新登录");

return false;

}

return true;

}

@Override

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {

}

@Override

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {

}

//返回错误信息

private static void setReturn(HttpServletResponse response, int status, String msg) throws IOException {

HttpServletResponse httpResponse = (HttpServletResponse) response;

httpResponse.setHeader("Access-Control-Allow-Credentials", "true");

httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtil.getOrigin());

//UTF-8编码

httpResponse.setCharacterEncoding("UTF-8");

response.setContentType("application/json;charset=utf-8");

Result build = Result.build(status, msg);

String json = JSON.toJSONString(build);

httpResponse.getWriter().print(json);

}

}

第二步,将拦截器配置进Spring

@Configuration

public class InterceptorConfig implements WebMvcConfigurer {

@Bean

public AuthInterceptor authInterceptor() {

return new AuthInterceptor();

}

@Override

public void addInterceptors(InterceptorRegistry registry) {

// 放行路径

List patterns = new ArrayList();

patterns.add("/webjars/**");

patterns.add("/druid/**");

patterns.add("/sys/login");

patterns.add("/swagger/**");

patterns.add("/v2/api-docs");

patterns.add("/swagger-ui.html");

patterns.add("/swagger-resources/**");

patterns.add("/login");

registry.addInterceptor(authInterceptor()).addPathPatterns("/**")

.excludePathPatterns(patterns);

}

}

第三步:测试

Controller 层

/**

* 登录校验

*/

@RestController("/")

public class AuthController {

@Autowired

private AuthService authService;

/**

* 登录

*

* @param loginDTO

* @return token登录凭证

*/

@PostMapping("/login")

public Result login(@RequestBody LoginDTO loginDTO) {

String username = loginDTO.getUsername();

String password = loginDTO.getPassword();

//用户信息

UserEntity user = authService.findByUsername(username);

//账号不存在、密码错误

if (user == null || !user.getPassword().equals(password)) {

return Result.build(400, "用户名或密码错误");

} else {

//生成token,并保存到数据库

String token = authService.createToken(user);

TokenVO tokenVO = new TokenVO();

tokenVO.setToken(token);

return Result.ok(tokenVO);

}

}

/**

* 登出

*

* @param

* @return

*/

@PostMapping("/logout")

public Result logout(HttpServletRequest request) {

//从request中取出token

String token = TokenUtil.getRequestToken(request);

authService.logout(token);

return Result.ok();

}

/**

* 测试

*

* @param

* @return

*/

@PostMapping("/test")

public Result test( ) {

return Result.ok("恭喜你,验证成功啦,我可以返回数据给你");

}

}

编写Service层

@Service

public class AuthServiceImpl implements AuthService {

@Autowired

private UserRepository userRepository;

@Override

public UserEntity findByUsername(String username) {

return userRepository.findByUsername(username);

}

//12小时后失效

private final static int EXPIRE = 12;

@Override

public String createToken(UserEntity user) {

//用UUID生成token

String token = UUID.randomUUID().toString();

//当前时间

LocalDateTime now = LocalDateTime.now();

//过期时间

LocalDateTime expireTime = now.plusHours(EXPIRE);

//保存到数据库

user.setLoginTime(now);

user.setExpireTime(expireTime);

user.setToken(token);

userRepository.save(user);

return token;

}

@Override

public void logout(String token) {

UserEntity userEntity = userRepository.findByToken(token);

//用UUID生成token

token = UUID.randomUUID().toString();

userEntity.setToken(token);

userRepository.save(userEntity);

}

@Override

public UserEntity findByToken(String token) {

return userRepository.findByToken(token);

}

}

然后启动项目即可

首先数据库保存一个用户,用户管理这里就不做啦。

我们来看看效果:使用Swagger查看效果

未登录状态下:

传递错误的token:

登录成功:

传递正确的token:

token过期之后

郑州不孕不育医院:http://www.xasgnk.com/

总结:如果你看过我那篇关于Shiro前后端分离的架构,其实很容易发现,这不就是简化版的Shiro吗?拦截、验证、返回错误信息。这就是思想上的一致。Shiro底层是用Filter(过滤器)、HandlerInterceptor底层是Interceptor(拦截器)。此外,本篇不仅仅可以实现登录拦截,对于权限拦截也是妥妥的,只需要再写一个拦截器,对权限进行验证,这里就不展开了。最主要还是前后端分离的思想,由前端控制路由,后端只负责返回对应信息,这肯定是发展趋势。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值