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对象格式