最近在接触spring security,它是个好东西,只是对Restful的支持并不是那么友好。对于习惯使用Restful接口的我,还是选择把spring security认证功能与RememberMe功能所用到的某些类进行重写,以实现spring security对Restful支持。
重写认证功能
1. 重写UsernamePasswordAuthenticationFilter
package com.tinyhelp.security;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tinyhelp.security.AuthenticationBean;
public class TinyHelpUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
@SuppressWarnings("finally")
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if(request != null && request.getMethod().equalsIgnoreCase("POST") &&
request.getContentType() != null &&
(request.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_UTF8_VALUE) ||
request.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE))) {
//当认证请求是JSON
//使用fastjson转换
ObjectMapper mapper = new ObjectMapper();
UsernamePasswordAuthenticationToken authRequest = null;
try (InputStream is = request.getInputStream()){
//忽略未知属性
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//读到认证Bean
AuthenticationBean authenticationBean = mapper.readValue(is,AuthenticationBean.class);
//生成认证令牌
authRequest = new UsernamePasswordAuthenticationToken(
authenticationBean.getPhoneNumber(), authenticationBean.getPassword());
}catch (IOException e) {
e.printStackTrace();
}finally {
//配置将request,authRequest注入到认证请求详情的属性中
setDetails(request, authRequest);
//返回认证后的身份
return this.getAuthenticationManager().authenticate(authRequest);
}
}
//否则非Json请求,使用原本的认证方式
return super.attemptAuthentication(request, response);
}
}
package com.tinyhelp.security;
/**
* 自定义认证Bean
*/
public class AuthenticationBean {
private String phoneNumber;
private String password;
private String rememberMe;
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRememberMe() {
return rememberMe;
}
public void setRememberMe(String rememberMe) {
this.rememberMe = rememberMe;
}
}
2. 将重写了的Filter在configure(HttpSecurity http)中配置
//自定义用户认证filter与原来的filter放在相同位置,但不覆盖原来的filter
http
.addFilterAt(tinyHelpUsernamePasswordAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class);
@Bean
TinyHelpUsernamePasswordAuthenticationFilter tinyHelpUsernamePasswordAuthenticationFilter() throws Exception {
TinyHelpUsernamePasswordAuthenticationFilter filter = new TinyHelpUsernamePasswo