续接第一篇文章的入门demo
为什么要自定义控制器Handler?
在上一篇的demo中,我们在登录成功后,跳转页面用到了successForwardUrl() ,表示成功后转发请求到地址。内部是通过 successHandler() 方法进行控制成功后交给哪个类进行处理
源码分析
可以看到sucessForwardUrl将forwordUrl 转发给ForwardAuthenticationSuccessHandler类进行处理
而ForwardAuthenticationSuccessHandler类的内部是简单的请求转发
当我们需要请求跳转到站外的地址或者在前后端分离的项目中登录请求跳转时,使用successForwardUrl()是不行的,这就需要我们去自定义控制器
自定义类
自定义登录成功处理器,重写AuthenticationSuccessHandler接口中的方法
package com.example.demo.handler;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//自定义登陆成功处理器
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private String url;
public MyAuthenticationSuccessHandler(String url) {
this.url = url;
}
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
System.out.println(httpServletRequest.getRemoteAddr());//获取ip地址
User user = (User)authentication.getPrincipal();//Principl主体存放了登录用户的信息
System.out.println(user.getAuthorities());//权限
System.out.println(user.getPassword());//出于安全考虑,输出null,无法查看
System.out.println(user.getUsername());
httpServletResponse.sendRedirect(url);//重定向至设定的url
}
}
Authentication源码
//源码
public interface Authentication extends Principal, Serializable {
Collection<? extends GrantedAuthority> getAuthorities();//获取权限
Object getCredentials();//获取凭证
Object getDetails();//获取详情
Object getPrincipal();//获取对象
boolean isAuthenticated();
void setAuthenticated(boolean var1) throws IllegalArgumentException;
}
同理 自定义登录失败处理器,重写AuthenticationFailureHandler接口中的方法
package com.example.demo.handler;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
private String url;
public MyAuthenticationFailureHandler(String url) {
this.url = url;
}
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.sendRedirect(url);
}
}
接下来需要去修改配置类,自定义控制器设定登录成功跳转到百度,登录失败跳转到知乎
package com.example.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
//自定义登录页
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http)throws Exception{
//登录
http.formLogin()
//自定义登录页面
.loginPage("/login.html")
//必须和表单提交的接口一致
.loginProcessingUrl("/login")
//登录成功跳转的页面,POST请求
//.successForwardUrl("/toMain")
//自定义登陆成功处理器
.successHandler(new MyAuthenticationSuccessHandler("https://www.baidu.com"))
//.successHandler(new MyAuthenticationSuccessHandler("/main.html"))
//登录失败后跳转的页面,post请求
//.failureForwardUrl("/toError")
//自定义登陆失败处理器
.failureHandler(new MyAuthenticationFailureHandler("https://www.zhihu.com"));
//.failureHandler(new MyAuthenticationFailureHandler("/error.html"));
//授权
http.authorizeRequests()
//放行login.html,无需验证
.antMatchers("/login.html").permitAll()
//放行error.html,无需验证
.antMatchers("/error.html").permitAll()
//所有请求都必须通过认证才能访问,(必须登录)
.anyRequest().authenticated();//拦截所有请求,有先后顺序,anyRequest()放在最后
//关闭csrf防护
http.csrf().disable();
}
@Bean
public PasswordEncoder getPw(){
return new BCryptPasswordEncoder();
}
}