前后端分離狀態下,后端SpringSecurity該如何變動呢? 如何變動取決於前后端分離狀態下,前后端交互的特點,純json交互,閑言少敘,上干貨
主配置類
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)// 開啟基於方法級別的防護
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
SecurityService securityService;
@Autowired
MyAuthenticationFailHandler myAuthenticationFailHandler;
@Autowired
MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(securityService)
.passwordEncoder(new BCryptPasswordEncoder());
}
@Bean
public AuthenticationEntryPoint macLoginUrlAuthenticationEntryPoint() {
return new MacLoginUrlAuthenticationEntryPoint();
}
// 安全配置項
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginPage("/login123")
.loginProcessingUrl("/user/login")// from表單中的action往這里提交
.usernameParameter("username").passwordParameter("password").permitAll()
.loginProcessingUrl("/login")
.successHandler(myAuthenticationSuccessHandler).failureHandler(myAuthenticationFailHandler)
.and()
.exceptionHandling().authenticationEntryPoint( macLoginUrlAuthenticationEntryPoint())
.and()
.authorizeRequests()// 禁用了 springSecurity , 允許一切請求
.antMatchers("/api/user/text1","/api/user/text2").hasRole("ADMIN")
.antMatchers("/api/user/text3").hasRole("USRE")
.anyRequest().permitAll() //
.and().csrf().disable();// todo
}
}
配置登錄成功處理器,響應給前端json
在前后端沒有分離時,用戶完成了登錄認證后,由后端的框架控制頁面的跳轉,但是前后端分離時,前后路由的跳轉后端不能干涉, 只能給前端用戶的信息等信息,由前端控制頁面的跳轉
@Component("MyAuthenticationSuccessHandler")
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Autowired
ObjectMapper mapper;
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
System.err.println("登錄成功 --- 返回json....");
// 允許跨域
httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
// 允許自定義請求頭token(允許head跨域)
httpServletResponse.setHeader("Access-Control-Allow-Headers", "token, Accept, Origin, X-Requested-With, Content-Type, Last-Modified");
httpServletResponse.setContentType("application/json;charset=UTF-8");
httpServletResponse.setStatus(200); // 成功返回200
Result result = new Result(200, "登錄成功", true, authentication.getPrincipal());
// 登錄成功
httpServletResponse.getWriter().write(mapper.writeValueAsString(result));
}
配置登錄失敗處理器,響應給前端json
登錄失敗,返回給前端失敗信息,及狀態碼
@Component("MyAuthenticationFailHandler")
public class MyAuthenticationFailHandler implements AuthenticationFailureHandler {
@Autowired
ObjectMapper mapper;
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
System.err.println("登錄失敗 -- 返回json....");
// 允許跨域
response.setHeader("Access-Control-Allow-Origin", "*");
// 允許自定義請求頭token(允許head跨域)
response.setHeader("Access-Control-Allow-Headers", "token, Accept, Origin, X-Requested-With, Content-Type, Last-Modified");
response.setStatus(201);
response.setContentType("application/json;charset=UTF-8");
if (e instanceof BadCredentialsException ||
e instanceof UsernameNotFoundException) {
response.getWriter().write(mapper.writeValueAsString("用戶名或密碼錯誤")); // 只返回異常消息
} else if (e instanceof LockedException) {
response.getWriter().write(mapper.writeValueAsString("賬戶被鎖定,請聯系管理員!")); // 只返回異常消息
} else if (e instanceof CredentialsExpiredException) {
response.getWriter().write(mapper.writeValueAsString("賬戶被鎖定,請聯系管理員!")); // 只返回異常消息
} else if (e instanceof AccountExpiredException) {
response.getWriter().write(mapper.writeValueAsString("賬戶過期,請聯系管理員!")); // 只返回異常消息
} else if (e instanceof DisabledException) {
response.getWriter().write(mapper.writeValueAsString("賬戶被禁用,請聯系管理員!")); // 只返回異常消息
} else {
response.getWriter().write(mapper.writeValueAsString("登錄失敗!")); // 只返回異常消息
}
}
}
當用戶沒有任何權限時,相應給前端json
默認情況下,當用戶沒有權限時,springsecurity 會將默認的無權限的頁面返回給前端,這個頁面巨丑,還會覆蓋原來的網頁,加入這個配置類實現返回由前端友情json提示
public class MacLoginUrlAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Autowired
ObjectMapper mapper;
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
// 允許跨域
response.setHeader("Access-Control-Allow-Origin", "*");
// 允許自定義請求頭token(允許head跨域)
response.setHeader("Access-Control-Allow-Headers", "token, Accept, Origin, X-Requested-With, Content-Type, Last-Modified");
response.setStatus(202);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(mapper.writeValueAsString("用戶相應的無權限,請聯系管理員")); // 只返回異常消息
}