SpringSecurity学习笔记之 入门 三 (前后端一体,的自定义页面403和login,,以及拦截策略的配置)

自定义403:

  • 首先需要自定义异常
/**
 * 自定义springboot错误处理异常
 */
@Configuration
public class WebSeverErrorConfig {
    //出现异常以后就会访问后面指定的路径
    @Bean
    public ConfigurableServletWebServerFactory webServerFactory(){
        TomcatServletWebServerFactory factory =new TomcatServletWebServerFactory();
        ErrorPage errorPage400=new ErrorPage(HttpStatus.BAD_REQUEST,"/error/400");
        ErrorPage errorPage401=new ErrorPage(HttpStatus.UNAUTHORIZED,"/error/401");
        ErrorPage errorPage403=new ErrorPage(HttpStatus.FORBIDDEN,"/error/403");
        ErrorPage errorPage404=new ErrorPage(HttpStatus.NOT_FOUND,"/error/404");
        ErrorPage errorPage415=new ErrorPage(HttpStatus.UNSUPPORTED_MEDIA_TYPE,"/error/415");
        ErrorPage errorPage500=new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR,"/error/500");
        factory.addErrorPages(errorPage400,errorPage401,errorPage403,errorPage404,errorPage415,errorPage500);
        return factory;
    }
}
  • 然后定义一个Controller接口,对应你设置的错误路径
@ResponseBody
@RequestMapping("/error/403")
public String error403() {
    return "权限不足";
}
也可以关闭body注解使用页面响应

自定义表单登录页面:

由于我们不是前后端分离的,这里我们随便准备一个简单的登录表单

<h1>登录页</h1>
<div>
    <form action="/login" method="post"> <!--提交路径,提交方式-->
        <div>账户:<input type="text" name="username"></div>
        <div>密码:<input type="text" name="password"></div>
        <input type="submit" value="登录"><!--提交按钮-->
    </form>
</div>
  • 注意用户名密码必须是username和password;

然后创建对应的接口
这里上面不能有@ResponsetBody或者@RestController,因为这里返回loging并不是返回login字符串,而是返回longin路径的页面;

@RequestMapping("/login")
public String login() {
    return "login.html";
}

在配置类中修改http对象

  1. 首先放开login路径的权限拦截,否则都被拦截了从何验证
 http.authorizeRequests().antMatchers("/login").permitAll()//可以直接在别的后面接续;
  1. 在配置完使用form表单验证的api后使用.调用loginPage(“”)配置验证路径并且修改.csrf().disable();
http.authorizeRequests().antMatchers("/**").fullyAuthenticated().and().formLogin()
						.loginPage("/login").and().csrf().disable();
  • 也就是说当访问login路径的时候就会访问到我们创建的接口并返回我们指定的登录界面,我们占用了默认的路径;然后表单提交的时候,就会提交到我们在配置类中配置的Login提交路径,会从中提取数据和内存中的用户信息进行比对;

在前后端分离中的配置

// 配置拦截规则,认证方式的方法
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // TODO 后续可以在redis中缓存,顺便也防止别有用心之人DDOS
        List<Auth> auths = authService.authFindAll();
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry
                eac = http.authorizeRequests();
        auths.forEach(auth -> {
            eac.antMatchers(auth.getUri()).hasAnyAuthority(auth.getAuthTag());
        });
        //前后端分离中,配置的登出登入跳转路由都可以用控制器替代,也可以共存
        eac.antMatchers("/user").permitAll()
                .antMatchers("/**").fullyAuthenticated().and().formLogin()
        /*登录*/
                //处理登录请求的接口
                .loginProcessingUrl("/user/login")
                //接收用户名的表单名称
                .usernameParameter("username")
                //接收密码的表单名称
                .passwordParameter("password")
                //登录成功后访问的路径
                .successForwardUrl("/user/loginSuccess")
                //登录失败后访问的路径
                .failureForwardUrl("/user/loginFailure")
                .permitAll();//配置完毕登录路径一律放行

        /*登出*/
        //退出登录时访问的路径
        http.logout().logoutUrl("/user/loginOut")
                //退出后访问的路径
                .logoutSuccessUrl("/user/loginOutSuccess")
                .permitAll();//配置完毕,退出一律放行


        /*异常处理*/
        //以下异常处理配置
        //未认证用户访问需要认证资源异常处理
               http.exceptionHandling().authenticationEntryPoint((httpServletRequest, httpServletResponse, e) -> {
            httpServletResponse.setContentType("application;charset=UTF-8");
            PrintWriter out = httpServletResponse.getWriter();
            out.print(JSON.toJSONString(new Result(false, CodeEnum.UN_LOGIN.code(), MsgEnum.UN_LOGIN.getCnMsg())));
            out.flush();
        })
                //认证用户访问资源权限不足异常处理
                .accessDeniedHandler((httpServletRequest, httpServletResponse, e) -> {
                    httpServletResponse.setContentType("application;charset=UTF-8");
                    PrintWriter out = httpServletResponse.getWriter();
                    out.print(JSON.toJSONString(new Result(false, CodeEnum.NO_PERMISSION.code(), MsgEnum.NO_PERMISSION.getCnMsg())));
                    out.flush();
                })
                //以上异常处理配置
                .and()
                .cors()//允许跨域,如果springboot/springmvc已有跨域配置,自动采用springboot/springmvc跨域配置
                .and()
                //禁用防CSRF攻击
                .csrf().disable();
    }

补充:security接受账号密码的方式为formData所以用常规post-json是无法让security接收到的;
需要使用formdata或者直接地址传参,可是为了保密性选择前者最好;
vue示例=>请求中加入参数:headers: { 'content-type': 'application/x-www-form-urlencoded' },

export function login(data) {
  return request({
    url: '/user/login',
    method: 'post',
    headers: { 'content-type': 'application/x-www-form-urlencoded' },
    data
  })
}

重要
关于配置的生效顺序

在这里,12可以访问,但是3无法访问;
猜测:从上到下配置规则。如果有重复的就重写之前的;

比如这样,在3被重写以后,3就可以访问了
可以的话用一句解决,里面传入数组;简单明了一点;

情况2:

1.2.3可以访问,4无法访问;
猜测:
他会像数组一样从前到后匹配。匹配得上就放行,匹配不上就直接403打回。。所以4在遇到/**以后就直接被打回了;

将all移下一行以后就会,在遇到all之前提前被放行

也就是说只要你在第一行配置了拦截所有/**,那第一个必定会碰到全部拦截。后面配置啥都没用; 同理只要你在拦截策略之前配置了放行全部。那么等于全部放行了啥都白瞎; 之前有幸配置了细化拦截的才会被拦截下来
(除非你拦截的时候把前面的/**重写了)

就像酱紫。别指望前面的没匹配上到了全部放行会放过你。因为他已经被后面的重写了;

总之他就是一个TreeMap集合,,会按照你存进去的顺序一个一个比较,但是又是一个去重集合,后面的会覆盖前面的;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值