使用ajax實(shí)現(xiàn)登錄退出那么就不要配置登錄成功或者失敗的url地址等等,只要使用successHandler或者failHandler配置處理器即可。
示列
- 加入maven依賴
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.0</version>
</dependency>
</dependencies>
<build>
<finalName>secuity-ajax-login-out</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.3.v20170317</version>
<configuration>
<httpConnector>
<port>8001</port>
</httpConnector>
<webApp>
<contextPath>/</contextPath>
</webApp>
</configuration>
</plugin>
</plugins>
</build>
- 實(shí)體類
因?yàn)槲沂褂胊jax登錄退出,所以我登錄退出成功失敗都是分別返回一個(gè)LoginResp實(shí)體和LogoutResp實(shí)體,實(shí)體定義如下:
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 {
}
- 定義系統(tǒng)啟動(dòng)類
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
//系統(tǒng)啟動(dòng)的時(shí)候的根類
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{WebAppConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
//設(shè)置成/*表示攔截靜態(tài)的文件
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
- web入口
/**
* 入口類,啟動(dòng)spring mvc,啟動(dòng)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", "用戶名或密碼錯(cuò)誤");
} else if(exp instanceof AccountExpiredException){
req.setAttribute("error_msg", "賬戶過(guò)期");
} else if(exp instanceof LockedException){
req.setAttribute("error_msg", "賬戶已被鎖");
}else{
//其他錯(cuò)誤打印這些信息
System.out.println(exp.getMessage());
}
return "/jsp/login";
}
}
- 權(quán)限相關(guān)配置類
登錄成功失敗后返回一個(gè)LoginResp對(duì)象的JSON類型到頁(yè)面上,退出成功失敗后返回一個(gè)LogoutResp對(duì)象的JSON類型到頁(yè)面上,
@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");
//登錄的跳轉(zhuǎn)頁(yè)面,和登錄的動(dòng)作url不應(yīng)該有權(quán)限認(rèn)證。
http.authorizeRequests().antMatchers("/sys/login").permitAll();
//配置登出頁(yè)面的跳轉(zhuǎn)url地址也有權(quán)限訪問(wèn),不去跳轉(zhuǎn)到登錄頁(yè)面
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") //登錄的按鈕執(zhí)行的動(dòng)作
.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("用戶名或密碼錯(cuò)誤");
} else if(excp instanceof AccountExpiredException){
lr.setMsg("賬戶過(guò)期");
} 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);
}
}
- 登錄頁(yè)面
login.jsp
<div class="login">
<h1>Login</h1>
<form method="post" action="/doLogin">
<input type="hidden" name="${ _csrf.parameterName}" value="${ _csrf.token}" />
<input type="text" name="username" placeholder="用戶名" />
<input type="password" name="password" placeholder="密碼"/>
<button type="button" onclick="doLogin()" class="btn btn-primary btn-block btn-large">登錄</button>
</form>
<div class="login-bottom" style="color:red;">${error_msg}</div>
</div>
<div style="text-align:center;">
</div>
</body>
<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript">
function doLogin(){
var _csrf = $('input[name=_csrf]').val();
var username = $('input[name=username]').val();
var password = $('input[name=password]').val();
var data = {_csrf:_csrf,username:username,password:password};
//登錄提交的url,在WebSecurityConfig配置類中配置了,登錄成功之后跳轉(zhuǎn)到/html/show.html頁(yè)面,此頁(yè)面也是登出頁(yè)面
$.post('/sys/doLogin', data, function(resp){
if(resp.code == 1){
alert('登陸成功');
window.location.href = "/html/show.html";
} else {
alert(resp.msg);
}
});
}
</script>
- 登出頁(yè)面
show.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>登陸成功</h1>
<hr />
<a href="#" onclick="doLogout()">logout</a>
</body>
<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript">
function doLogout(){
var data = {};
//配置的登出的url,
$.get('/sys/doLogout', data, function(resp){
if(resp.code == 1){
alert('退出成功');
window.location.href = "/hello";
} else {
alert(resp.msg);
}
});
}
</script>
</html>
- 啟動(dòng)服務(wù),測(cè)試一下
訪問(wèn)http://localhost:8001/hello,跳轉(zhuǎn)到登錄頁(yè)面http://localhost:8001/sys/login,輸入正確的用戶名密碼之后頁(yè)面彈出登陸成功,點(diǎn)擊確認(rèn)之后跳轉(zhuǎn)到http://localhost:8001/html/show.html(也就是我們的退出頁(yè)面)

驗(yàn)證用戶名密碼成功之后,頁(yè)面彈出登錄成功

登錄成功之后點(diǎn)擊確認(rèn)跳轉(zhuǎn)的接口,點(diǎn)擊logout退出,
退出成功之后頁(yè)面彈出退出成功,點(diǎn)擊確認(rèn)之后跳轉(zhuǎn)到登錄頁(yè)面

退出成功之后頁(yè)面彈出退出成功,點(diǎn)擊確認(rèn)之后跳轉(zhuǎn)到登錄頁(yè)面