Spring Security 登录使用body参数手机号+验证

2022-03-07  本文已影响0人  光芒121

Spring Security 默认的formLogin登录传参是2个默认的字段,那就是username、password,并且也不是json格式,很多时候我们的业务使用都是phone和code字段,并且是接收对象,那么这时候就要重写相关的类来达到我们的效果了。


默认的 login 定义的参数源码

我们从源码中可以看到,默认的security登录帮我们实现了 "/login" 方法,也就是 UsernamePasswordAuthenticationFilter 类中定义的参数也都帮我们设置好了,所以我们传参时候想要其他格式的就得去重写 AbstractAuthenticationProcessingFilter 类去实现我们自己的名字和字段格式

Security配置类

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final RequestCallbackHandler handler;
    private final LoginConfigurerAdapter adapter;

    public SecurityConfig(RequestCallbackHandler handler, LoginConfigurerAdapter adapter) {
        this.handler = handler;
        this.adapter = adapter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //添加转码
        CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding("UTF-8");
        encodingFilter.setForceEncoding(true);
        http.addFilterBefore(encodingFilter, CsrfFilter.class);
        //关闭跨域请求
        http.csrf().disable();
        http.authorizeRequests()
                .antMatchers("/my/login").permitAll()
                //登录之外的都需要进行验证
                .anyRequest().authenticated()
                .and().apply(adapter)
                .and()
                .exceptionHandling()
                //没有登录回调
                .authenticationEntryPoint(handler);
    }
}

重点设置接收body参数的地方:

public class LoginProcessingFilter extends AbstractAuthenticationProcessingFilter {

    //把你们的登录地址写在此处 “/my/login” 等随意登录名字
    private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER =
            new AntPathRequestMatcher("/my/login", "POST");

    protected LoginProcessingFilter() {
        super(DEFAULT_ANT_PATH_REQUEST_MATCHER);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        if (!request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("不支持身份验证方法:" + request.getMethod());
        }
        String bodyString = getBodyString(request);
        String phone = null;
        String code = null;
        if (!StringUtils.isBlank(bodyString)) {
            //json转 LoginUserLoginVO 对象
            Gson gson = new Gson();
            LoginUserVO loginUserVO = gson.fromJson(bodyString, LoginUserVO.class);
            if (loginUserVO != null) {
                //获取传递的手机号
                phone = loginUserVO.getPhone();
                //获取传递的验证码
                code = loginUserVO.getCode();
            }
        }
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(phone, code);
        return this.getAuthenticationManager().authenticate(authenticationToken);
    }

    /**
     * 接收传递的jsonBody类型的参数
     */
    public String getBodyString(HttpServletRequest request) throws IOException {
        StringBuilder sb = new StringBuilder();
        InputStream inputStream = null;
        BufferedReader reader = null;
        try {
            inputStream = request.getInputStream();
            reader = new BufferedReader(
                    new InputStreamReader(inputStream, StandardCharsets.UTF_8));

            char[] bodyCharBuffer = new char[1024];
            int len = 0;
            while ((len = reader.read(bodyCharBuffer)) != -1) {
                sb.append(new String(bodyCharBuffer, 0, len));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }
}

手机号和验证码逻辑判断处:

public class LoginAuthenticationProvider implements AuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        //用户名、手机号
        String phone = (String) authentication.getPrincipal();
        //密码、验证码
        String code = (String) authentication.getCredentials();
        if (StringUtils.isBlank(phone)) {
            throw new UsernameNotFoundException("手机号不能为空");
        }
        if (!phone.equals("123")) {    //正常去查询数据库
            throw new UsernameNotFoundException("用户不存在");
        }
        if (StringUtils.isBlank(code) || !code.equals("123456")) {
            throw new BadCredentialsException("验证码不正确");
        }
        return new UsernamePasswordAuthenticationToken(phone, code, null);
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return true;
    }
}
请求登录接口时候传递json对象格式
上一篇下一篇

猜你喜欢

热点阅读