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

之前写过一篇关于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<String> 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层

扫描二维码关注公众号,回复: 10430871 查看本文章
@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过期之后

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


有什么问题可以评论或者私信我,每日在线解(LIAO)疑(SAO)。

这里是大誌的博客,一位初生的卑微码农,觉得好用记得点赞!!!

发布了77 篇原创文章 · 获赞 62 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/weixin_42236404/article/details/105252892