前言

最近手上有个项目,采用前后端分离的模式开发,前端使用vue 后端采用springBoot+springSecurity。最近开发就遇到个十分简单,但是由困了我两天的问题。我本着不掉光头发誓不罢休的原则,开始了苦逼的找bug日常。


一、问题描述

springSecurity自定义的登录框,获取不到用户名和密码。
实际开发中我们不太可能使用springSecurity自带的登录界面,所以我们一般会使用自定义的登录界面。为了展示效果,我简单的写了一个极其丑陋的登录界面,如下

<template>
  <div id="app" style="align-content: center">
    <span><h1>登录</h1></span>
    <el-form :label-position="labelPosition" label-width="80px" :model="formLabelAlign">
      <el-form-item label="用户名">
        <el-input v-model="formLabelAlign.username" style="width:300px"></el-input>
      </el-form-item>
      <el-form-item label="密码">
        <el-input v-model="formLabelAlign.password"  style="width:300px"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="onSubmit">登录</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

还有个点击事件—点击登录发起的请求

 onSubmit() {
      this.$axios.post("http://localhost:8082/login", this.formLabelAlign,{
        headers:{
          'Content-Type':'application/x-www-form-urlencoded'
        }
      }).then(res => {
        console.log(res);
      })

在webSecurityConfig中配置拦截规则

protected void configure(HttpSecurity http) throws Exception {
       http.cors().and()
               .authorizeRequests()
               .antMatchers("/login").permitAll()
               .antMatchers("/**").hasRole("nomal")
               .and().formLogin().loginProcessingUrl("/login").permitAll()
               .successHandler(new AuthenticationSuccessHandlerImpl())
               .failureHandler(new AuthenticationFailureHandlerImpl())
               .and().logout().logoutUrl("/logout").permitAll()
               .logoutSuccessHandler(new LogoutSuccessHandlerImpl())
               .and().csrf().disable().exceptionHandling();
    }

进过一番的配置,之后开心地去测试。每次都登录失败。
为了测试,我在自定义的provider中加入了打印登录的信息。

package com.yzm.spring_secrurity;

import com.yzm.spring_secrurity.pojo.UserInfo;
import com.yzm.spring_secrurity.service.MyUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.Collection;

@Component
public class MyAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private MyUserDetailService myUserDetailService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String name = authentication.getName();
        String password = (String) authentication.getCredentials();
        System.out.println("name is  "+name);
        System.out.println("password is  "+password);
        UserInfo userInfo = (UserInfo) myUserDetailService.loadUserByUsername(name);
        if (userInfo == null){
            throw new BadCredentialsException("用户名不存在");
        }
        if (!userInfo.getPassword().equals(password)){
            throw new BadCredentialsException("密码错误");
        }
        Collection<? extends GrantedAuthority> authorities = userInfo.getAuthorities();

        return new UsernamePasswordAuthenticationToken(userInfo,password,authorities);
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }
}

输入用户名和密码后,后台打印结果
运行结果

二、查找原因

我知道,登录验证的是由 UsernamePasswordAuthenticationFilter处理的
在这里插入图片描述
在这个过滤器中我们可以看到参数名如果自己没有配置就必须是(username,password),登录必须是post请求,并且请求路径一定是login(当然可以修改)。我们还看到了获取用户名和密码的方法obtainUsername、obtainPassword,点进去看了一,我彻底懵了(醒悟了)。
在这里插入图片描述
这居然是我学javaWeb用的最多的方法request.getParameter(),post怎么获取不到呢???,查了无数的资料,他们说contentType的原因。但是可以看到,我修改了的,不起效(这我不知道原因),后来有人说用qs可以,将参数以&连接到网址后面。这样就可以获取到。

三、解决

安装qs

npm install qs

在main.js中添加

import qs from 'qs'
Vue.prototype.$qs=qs

最后修改请求

onSubmit() {
      this.$axios.post("http://localhost:8082/login", this.$qs.stringify(this.formLabelAlign),{
        headers:{
          'Content-Type':'application/x-www-form-urlencoded'
        }
      }).then(res => {
        console.log(res);
      })
    }

在此点击登录,就可看到后台获取到了用户名和密码
运行结果


总结

使用request.getParameter获取参数值,这样方式在get请求中屡试不爽,而且非常好用,因为get的参数就是url后面,可以和方便的取到,但是post请求里面的参数是不一样的,要么使用qs进行转换,要么就自己封装下。最后还是说一句,读源码实在是太重要了,如果没看到源码,这个问题不知道要困我多久。

Logo

前往低代码交流专区

更多推荐