1. 新建项目,导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2. 启动类
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
3. 在UsernamePasswordAuthenticationFilter中我们可以看到,登录的请求为/login,请求方式为post,同时还看到定义的登录的用户名密码为username, password。这些东西都是可以改的。我们写一个类继承UsernamePasswordAuthenticationFilter,写逻辑覆盖需要修改的东西即可。
public class MyAuthencationFilter extends UsernamePasswordAuthenticationFilter {
/**
* 如果不需要json登录方式可以不重写此方法
*/
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
//判断是否是JSON登录
String contentType = request.getContentType();
if (MediaType.APPLICATION_JSON_UTF8_VALUE.equalsIgnoreCase(contentType)
|| "application/json; charset=UTF-8".equalsIgnoreCase(contentType)
|| MediaType.APPLICATION_JSON_VALUE.equals(contentType)) {
try {
//获取提交的JSON数据
ServletInputStream ris = request.getInputStream();
StringBuilder content = new StringBuilder();
byte[] b = new byte[1024];
int lens;
while ((lens = ris.read(b)) > 0) {
content.append(new String(b, 0, lens));
}
//从JSON数据中获取用户名和密码
JSONObject dataObject = JSONObject.parseObject(content.toString());
// 这里的username和password也可以自己指定名称,那么登录的时候就用指定的就行了
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
dataObject.getString("username"), dataObject.getString("password"));
setDetails(request, token);
return this.getAuthenticationManager().authenticate(token);
} catch ( IOException e) {
return super.attemptAuthentication(request, response);
}
} else {
return super.attemptAuthentication(request, response);
}
}
}
4.写一个类继承WebSecurityConfigurerAdapter,自定义一些security配置信息。
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
// 自定义登录成功处理器,可以处理登录成功时的逻辑,也可不写
@Autowired
private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
// 自定义登录失败处理器,可以处理登录失败时的逻辑,也可不写
@Autowired
private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
// 自定义登出成功处理器,可以处理登出成功时的逻辑,也可不写
@Autowired
private MyLogoutSuccessHandler myLogoutSuccessHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.logout()
.logoutSuccessHandler(myLogoutSuccessHandler);
http.addFilterAt(myAuthencationFilter(), UsernamePasswordAuthenticationFilter.class);
http.addFilterAt(myAuthencationFilter2(), UsernamePasswordAuthenticationFilter.class);
http.addFilterAt(myAuthencationFilter3(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
MyAuthencationFilter myAuthencationFilter() throws Exception {
MyAuthencationFilter filter = new MyAuthencationFilter();
filter.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler);
filter.setAuthenticationFailureHandler(myAuthenticationFailureHandler);
filter.setFilterProcessesUrl("/login/page1");
filter.setAuthenticationManager(authenticationManagerBean());
return filter;
}
@Bean
MyAuthencationFilter myAuthencationFilter2() throws Exception {
MyAuthencationFilter filter = new MyAuthencationFilter();
filter.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler);
filter.setAuthenticationFailureHandler(myAuthenticationFailureHandler);
filter.setFilterProcessesUrl("/login/page2");
filter.setAuthenticationManager(authenticationManagerBean());
return filter;
}
@Bean
MyAuthencationFilter myAuthencationFilter3() throws Exception {
MyAuthencationFilter filter = new MyAuthencationFilter();
filter.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler);
filter.setAuthenticationFailureHandler(myAuthenticationFailureHandler);
filter.setFilterProcessesUrl("/login/page3");
filter.setAuthenticationManager(authenticationManagerBean());
return filter;
}
}
5.自定义登录成功处理器,在Authentication对象中会封装用户信息,需要可以使用其getPrincipal()方法获取。
@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private ObjectMapper mapper = new ObjectMapper();
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
// 以json格式返回数据
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(mapper.writeValueAsString("登录成功"));
response.getWriter().close();
}
}
6.自定义登录失败处理器,实现方法后可以写登录失败的日志等信息,AuthenticationException 中会封装异常信息。
@Component
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
private ObjectMapper mapper = new ObjectMapper();
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(mapper.writeValueAsString("登录失败"));
response.getWriter().close();
}
}
7.自定义登出成功处理器,这里退出登录时使用json格式返回,也可以自定义一些东西,如输出日志等。
@Component
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
private ObjectMapper mapper = new ObjectMapper();
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
// 以json格式返回数据
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(mapper.writeValueAsString("登出成功"));
}
}
8.定义controller
@RestController
public class SecurityController {
@GetMapping("/api/fun")
public String fun() {
return "hello";
}
}
9. 访问/api/fun,由于没登录会跳转到登录页面,也可以通过/login/page1登录,以json格式传入参数(默认用户名是user,密码是项目启动时控制台打印的密码),如下:
10. 退出后可以用/login/page2或/login/page3进行登录。