使用ajax实现登录退出那么就不要配置登录成功或者失败的url地址等等,只要使用successHandler
或者failHandler
配置处理器即可。
示列
- 加入maven依赖
org.springframework
spring-webmvc
4.3.13.RELEASE
org.springframework.security
spring-security-web
4.2.3.RELEASE
org.springframework.security
spring-security-config
4.2.3.RELEASE
javax.servlet
javax.servlet-api
3.1.0
provided
javax.servlet.jsp
jsp-api
2.2
provided
com.google.code.gson
gson
2.8.0
secuity-ajax-login-out
org.apache.maven.plugins
maven-war-plugin
3.0.0
false
org.eclipse.jetty
jetty-maven-plugin
9.4.3.v20170317
8001
/
- 实体类
因为我使用ajax登录退出,所以我登录退出成功失败都是分别返回一个LoginResp
实体和LogoutResp
实体,实体定义如下:
LoginResp
public class LoginResp {
private Integer code;
private String msg;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public LoginResp(){}
public LoginResp(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
}
LogoutResp
public class LogoutResp extends LoginResp {
}
- 定义系统启动类
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
//系统启动的时候的根类
@Override
protected Class>[] getRootConfigClasses() {
return new Class>[]{WebAppConfig.class};
}
@Override
protected Class>[] getServletConfigClasses() {
return null;
}
//设置成/*表示拦截静态的文件
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
- web入口
/**
* 入口类,启动spring mvc,启动spring secuity
*/
@EnableWebMvc
@EnableWebSecurity
@ComponentScan("com.zhihao.miao.secuity")
public class WebAppConfig extends WebMvcConfigurerAdapter {
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
//配置视图解析器
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp();
}
}
- spring security配置类
/**
* 初始化spring security
*/
public class WebAppSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
protected String getDispatcherWebApplicationContextSuffix() {
return AbstractDispatcherServletInitializer.DEFAULT_SERVLET_NAME;
}
}
- 具体的controller
HelloController:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(){
return "hello spring secuity";
}
@GetMapping("/home")
public String home(){
return "home spring security";
}
@GetMapping("/admin")
public String admin(){
return "admin spring secuity";
}
}
LoginController:
@Controller
public class LoginController {
@GetMapping("/sys/login")
public String login(){
return "/jsp/login";
}
@GetMapping("/sys/logout")
public String logout(){
return "/jsp/logout";
}
@PostMapping("/sys/loginFail")
public String fail(HttpServletRequest req){
AuthenticationException exp = (AuthenticationException)req.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
if(exp instanceof BadCredentialsException){
req.setAttribute("error_msg", "用户名或密码错误");
} else if(exp instanceof AccountExpiredException){
req.setAttribute("error_msg", "账户过期");
} else if(exp instanceof LockedException){
req.setAttribute("error_msg", "账户已被锁");
}else{
//其他错误打印这些信息
System.out.println(exp.getMessage());
}
return "/jsp/login";
}
}
- 权限相关配置类
登录成功失败后返回一个LoginResp
对象的JSON类型到页面上,退出成功失败后返回一个LogoutResp
对象的JSON类型到页面上,
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("zhangsan").password("123456").roles("GUEST");
auth.inMemoryAuthentication().withUser("zhihao.miao").password("123456").roles("USER");
auth.inMemoryAuthentication().withUser("lisi").password("12345678").roles("USER", "ADMIN");
}
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/hello").hasRole("GUEST");
http.authorizeRequests().antMatchers("/home").hasRole("USER");
http.authorizeRequests().antMatchers("/admin").hasRole("ADMIN");
//登录的跳转页面,和登录的动作url不应该有权限认证。
http.authorizeRequests().antMatchers("/sys/login").permitAll();
//配置登出页面的跳转url地址也有权限访问,不去跳转到登录页面
http.authorizeRequests().antMatchers("/sys/logout").permitAll();
http.authorizeRequests().antMatchers("/**/*.html").permitAll();
http.authorizeRequests().antMatchers("/**/*.css").permitAll();
http.authorizeRequests().antMatchers("/**/*.js").permitAll();
http.authorizeRequests().antMatchers("/**/*.png").access("permitAll");
http.authorizeRequests().anyRequest().authenticated();
http.formLogin()
.loginPage("/sys/login")
.loginProcessingUrl("/sys/doLogin") //登录的按钮执行的动作
.successHandler((req, resp, auth) -> {
LoginResp lr = new LoginResp(1, "用户登陆成功");
String json = new Gson().toJson(lr);
resp.setContentType("application/json");
resp.getWriter().write(json);
})
.failureHandler((req, resp, excp) -> {
LoginResp lr = new LoginResp();
lr.setCode(0);
if(excp instanceof BadCredentialsException){
lr.setMsg("用户名或密码错误");
} else if(excp instanceof AccountExpiredException){
lr.setMsg("账户过期");
} else if(excp instanceof LockedException){
lr.setMsg("账户已被锁");
} else {
lr.setMsg("用户登陆失败");
}
String json = new Gson().toJson(lr);
resp.setContentType("application/json");
resp.getWriter().write(json);
})
.permitAll();
http.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/sys/doLogout", "GET")) //支持定制退出url以及httpmethod
.logoutSuccessHandler((req, resp, auth) -> {
LogoutResp lr = new LogoutResp();
lr.setCode(1);
lr.setMsg("用户退出成功");
String json = new Gson().toJson(lr);
resp.setContentType("application/json");
resp.getWriter().write(json);
})
.clearAuthentication(true)
.invalidateHttpSession(true);
}
}
- 登录页面
login.jsp
Login
${error_msg}