java解决限制访问指定url

  • Post author:
  • Post category:java




前言

在web项目交付阶段,很多交付的小伙伴们会面临的一个问题就是安全漏洞扫描,关于安全漏洞问题,可以分为很多种,但从扫描者的角度,一旦他们认为你的后端服务接口暴露的太多,或过于明显,或没有前置的安全措施(通过登录的方式)就能拿到后台的数据,这样显然是不合理的,一旦扫出这样的接口,那么面临的一个问题就是,解决接口暴露的问题

关于这个问题,其实说起来,还是跟系统在一开始的规划设计阶段的安全考虑不够完备,比如你的后台项目是否需要做必要的鉴权,是否集成了第三方安全框架等,如果在项目框架搭建之初,就能考虑到这些问题,相信在后续的交付阶段,就不必担心接口的安全漏洞问题

但不管如何,一旦出现了,既然不能推倒重来,我们还必须要想办法快速补救,下面就本人在项目交付阶段的一点零碎的经验,针对这个问题,做一点技术实现方案的总结



方案1:使用过滤器

这种方式最简单,对大多数程序员来说,也最容易实现,只需要在一个自定义过滤器中,针对所有请求后端服务的url做拦截,对后端所有的URL进行分类,不同的url必须要经过什么样的校验才能通过,这种方式比较简单,就不再做代码层面的展示了



方案2:使用拦截器

先贴上代码

package com.congge.interceptor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {

    public static Logger logger = LoggerFactory.getLogger(MyInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.info("执行 preHandle:{}",request.getRequestURI());
        //TODO 这里可以是token,权限等前置业务的处理......
        response.getWriter().write("you have no access");
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        logger.info("执行 preHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        logger.info("执行 afterCompletion");
    }

}

package com.congge.interceptor;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

@Configuration
public class MyWebmvcConfig extends WebMvcConfigurationSupport {

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/user/**", "/admin/**", "/account/**")    //哪些路径要拦截
                .excludePathPatterns("/open/api/**");                         //哪些逻辑不需要做拦截
    }

    /**
     * 静态资源的访问
     * @param registry
     */
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/");
        registry.addResourceHandler("/templates/**")
                .addResourceLocations("classpath:/templates/");
        super.addResourceHandlers(registry);
    }

}

定义一个拦截器,实现HandlerInterceptor接口,在重新的方法中,编写自身校验权限,token等逻辑,如果返回false,请求直接结束,否则可以进入后续的接口资源访问,以文中的配置为例,我们分别访问一下2个接口

在这里插入图片描述

在这里插入图片描述

上面这种方式的改造成本比较小,实现难度也很小,可以作为第一选择



方案3:集成shiro

相信很多小伙伴都用过shiro,shiro是一个小巧适用的安全框架,但实际上来说,在和后端项目进行集成时,很多前置的配置工作要做,而且和数据库的权限认证那一套的表结合的很紧密,如果不是在设计之初就集成的话,这个改造的难度和复杂度还是比较大的,慎用



方案4:集成spring-security

一听到spring-security,很多同学开始谈虎色变了,spring-security在后端的框架中算是比较复杂,也比较重型的框架了,学习成本是比较高的,但经过本人的研究发现,如果并不打算完全将spring-security的安全体系替换现有的代码逻辑时,可以借助其部分针对接口资源的权限控制功能,完全可以达到本篇问题的目的,下面通过2种方式来快速说明下

导入security依赖

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>


方式1:直接引用上面的依赖之后,在配置文件中做简单的配置即可

#手动设置登录用户名和密码
spring.security.user.name=admin
spring.security.user.password=admin

引入依赖之后,项目启动之后,访问后端接口时,所有的请求都要经过spring-security的默认登录页面,因此上述配置文件中配置的用户名和密码即为登录的用户名和密码

当我们再次访问上面的接口时,就会弹出下面的登录页面

在这里插入图片描述

输入:root/root,即可正常访问接口了

在这里插入图片描述

但这种方式的使用场景比较有限,使用的时候请慎重考虑


方式2:使用spring-security的安全配置策略

spring-security集成了很多功能,比如像权限,角色控制等,一般来说,任何系统的登录功能是必不可少的,因此可以借助系统现有的登录登录,再融入spring-security的登录认证即可满足

实现起来,主要包括如下几点,

1)自定义UserDetailsService,即实现UserDetailsService接口

@Configuration("userDetailsService")
public class MyUserDetailService implements UserDetailsService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        QueryWrapper<MyUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",username);
        MyUser myUser = userMapper.selectOne(queryWrapper);
        if(myUser==null){
            throw new RuntimeException("该用户不存在");
        }
        List<GrantedAuthority> roles = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
        return new User(username,new BCryptPasswordEncoder().encode(myUser.getPassword()),roles);
    }
}

2)自定义配置类,继承WebSecurityConfigurerAdapter,根据需要重写里面的相关方法即可

@Configuration

public class MySecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private MyUserDetailService userDetailService;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailService).passwordEncoder(password());
}

@Bean
public PasswordEncoder password() {
    return new BCryptPasswordEncoder();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.formLogin()
                .loginPage("/login.html")                       //自定义的登录界面
                .loginProcessingUrl("/user/login")              //登录提交的接口
                .defaultSuccessUrl("/zcy/index").permitAll()    //登录成功之后默认的跳转路径
            .and().authorizeRequests()                           //自定义受保护的URL资源
                .antMatchers("/","/user/login","/open/api/**")
                .permitAll()                                    //设置那些URL路径可以直接访问,不需要认证
                .anyRequest().authenticated()                   //除了上面其他的URL资源都受保护
            .and()
                .csrf().disable();                              //关闭CSRF防护
}

}

关于上面的这段配置,相信的使用说明,有兴趣的同学可以参考我的专栏文章:

spring-security

总体的逻辑就是,在自定义的MyUserDetailService 中,完成登录的业务,只有查到访问资源的请求用户存在才会进入到下一步,当然在这个类中,可以结合现有系统的角色,权限体系做进一步的整合,而MySecurityConfig这个类,控制对访问的URL做保护,规定了哪些URL需要走登录认证,哪些可以不用认证等配置信息

启动项目之后,让我们来做一下测试吧,分别访问一下下面的接口

http://localhost:8081/open/api/user-info

http://localhost:8081/account/get/list

接口1可以直接访问,因为在配置类中对接口直接放行了

在这里插入图片描述

访问接口2的时候,弹出了如下的自定义登录页面

在这里插入图片描述

在这里插入图片描述

在数据库中有这样一个用户,我们输入用户名和密码,就可以访问到该接口了

在这里插入图片描述


本篇总结了几种常用的限制访问后端URL的方式,希望对看到的小伙伴们有用,本篇到此结束,最后感谢观看!



版权声明:本文为zhangcongyi420原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。