I am writing rest
service with json
. For backend I use Spring Security
. I have form witch sends with ajax rest object as follow:
You can extend and override WebSecurityConfigurerAdapter
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.addFilter(new UserNamePasswordAuthFilter(authenticationManager(), userRepo))
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(daoAuthenticationProvider());
}
@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService); // custom user service
provider.setPasswordEncoder(passwordEncoder); // custom password encoder
return provider;
}
Then you can define a filter for authentication and optionally you can override successful login behavior.
public class UserNamePasswordAuthFilter extends UsernamePasswordAuthenticationFilter {
private final AuthenticationManager authManager;
private final AecUserRepo userRepo;
public UserNamePasswordAuthFilter(AuthenticationManager authManager, AecUserRepo userRepo) {
super();
this.authManager = authManager;
this.userRepo = userRepo;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
try {
// Get username & password from request (JSON) any way you like
UsernamePassword authRequest = new ObjectMapper()
.readValue(request.getInputStream(), UsernamePassword.class);
Authentication auth = new UsernamePasswordAuthenticationToken(authRequest.getUsername(),
authRequest.getPassword());
return authManager.authenticate(auth);
} catch (Exception exp) {
throw new RuntimeException(exp);
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response, FilterChain chain, Authentication authResult)
throws IOException, ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Authentication success. Updating SecurityContextHolder to contain: "
+ authResult);
}
// custom code
SecurityContextHolder.getContext().setAuthentication(authResult);
}
}
Well, it must not work until you write the getUserNamePasswordAuthenticationToken body.
Actually, you must read the request body of the HttpServletRequest, parse it through Jackson or any other mapping way and create with it the UsernamePasswordAuthenticationToken.
Using Jackson (choose the right version depending on your Spring version), I would create a simple bean like this:
@JsonIgnoreProperties(ignoreUnkown=true)
public LoginRequest{
private String email;
private String password;
// getters & setters
}
The use it to map it the request body:
private UsernamePasswordAuthenticationToken getUserNamePasswordAuthenticationToken(HttpServletRequest request) throws IOException{
StringBuffer sb = new StringBuffer();
BufferedReader bufferedReader = null;
String content = "";
LoginRequest sr = null;
try {
bufferedReader = request.getReader()
char[] charBuffer = new char[128];
int bytesRead;
while ( (bytesRead = bufferedReader.read(charBuffer)) != -1 ) {
sb.append(charBuffer, 0, bytesRead);
}
content = sb.toString();
ObjectMapper objectMapper = new ObjectMapper();
try{
sr = objectMapper.readValue(content, LoginRequest.class);
}catch(Throwable t){
throw new IOException(t.getMessage(), t);
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
throw ex;
}
}
}
return new UsernamePasswordAuthenticationToken(sr.getEmail(), sr.getPassword());
}
P.D. Yo must use Post, you will never be able to post a request-body using GET