1.问题描述
调用SpringSecurity登录接口成功了,但是我去访问其他接口的时候,一直说我未认证
我的代码 继承了 UsernamePasswordAuthenticationFilter 类 下面是我的源代码
package com.security.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* @Description:自定义登录拦截过滤器
*/
public class LoginFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
// 1、判断是否是 POST 请求方式
if (!"POST".equals(request.getMethod())) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
String username = null;
String password = null;
try {
// 2、判断是否是 JSON 的格式
if (request.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_UTF8_VALUE) || request.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE)) {
// 3、从 json 数据中获取用户输入的用户名和密码进行认证
HashMap<String, String> map = new ObjectMapper().readValue(request.getInputStream(), HashMap.class);
username = map.get("username");
password = map.get("password");
if (username == null || password == null) {
throw new RuntimeException("用户名或者密码错误");
}
}
} catch (IOException e) {
e.printStackTrace();
}
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
Authentication authenticate = this.getAuthenticationManager().authenticate(authRequest);
return authenticate;
}
@Override
protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
super.setDetails(request, authRequest);
}
// 自定义认证成功处理
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
Map<String, Object> result = new HashMap<String, Object>();
result.put("msg", "登录成功");
result.put("用户信息", authResult.getPrincipal());
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpStatus.OK.value());
String s = new ObjectMapper().writeValueAsString(result);
response.getWriter().println(s);
}
// 自定义认证失败处理
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
Map<String, Object> result = new HashMap<String, Object>();
result.put("msg", "登录失败: " + failed.getMessage());
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
response.setContentType("application/json;charset=UTF-8");
String s = new ObjectMapper().writeValueAsString(result);
response.getWriter().println(s);
}
}
2.导致问题的代码
从上面代码就可以看出来,我本来是想重写登录成功后的返回信息,就是返回自定义的信息,
我这里重写的是 successfulAuthentication 方法
让我们看下 security的源码
很显然问题就是 我没有 初始化 SecurityContex
3.解决方案
如果只是重写 security 的登录信息的话,
把successfulAuthentication 和 unsuccessfulAuthentication 修改成下面两个方法
setAuthenticationSuccessHandler 和 setAuthenticationFailureHandler
package com.security.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* @Description:自定义登录拦截过滤器
*/
public class LoginFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
// 1、判断是否是 POST 请求方式
if (!"POST".equals(request.getMethod())) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
String username = null;
String password = null;
try {
// 2、判断是否是 JSON 的格式
if (request.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_UTF8_VALUE) || request.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE)) {
// 3、从 json 数据中获取用户输入的用户名和密码进行认证
HashMap<String, String> map = new ObjectMapper().readValue(request.getInputStream(), HashMap.class);
username = map.get("username");
password = map.get("password");
if (username == null || password == null) {
throw new RuntimeException("用户名或者密码错误");
}
}
} catch (IOException e) {
e.printStackTrace();
}
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
Authentication authenticate = this.getAuthenticationManager().authenticate(authRequest);
return authenticate;
}
// 重写登录成功后的返回信息
@Override
public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler successHandler) {
AuthenticationSuccessHandler authenticationSuccessHandler = new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
Map<String, Object> result = new HashMap<String, Object>();
result.put("msg", "登录成功");
result.put("用户信息", authentication.getPrincipal());
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpStatus.OK.value());
String s = new ObjectMapper().writeValueAsString(result);
response.getWriter().println(s);
}
};
super.setAuthenticationSuccessHandler(authenticationSuccessHandler);
}
// 重写登录失败的返回信息
@Override
public void setAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
AuthenticationFailureHandler authenticationFailureHandler = new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
Map<String, Object> result = new HashMap<String, Object>();
result.put("msg", "登录失败: " + exception.getMessage());
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
response.setContentType("application/json;charset=UTF-8");
String s = new ObjectMapper().writeValueAsString(result);
response.getWriter().println(s);
}
};
super.setAuthenticationFailureHandler(authenticationFailureHandler);
}
}