package com.ks.app.config; import com.google.code.kaptcha.Producer; import com.google.code.kaptcha.impl.DefaultKaptcha; import com.google.code.kaptcha.util.Config; import com.ks.app.entity.AdminUser; import com.ks.app.service.inter.AdminUserService; import net.sf.json.JSONObject; import org.omg.CORBA.SystemException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import org.springframework.web.filter.OncePerRequestFilter; import org.yeshi.utils.JsonUtil; import org.yeshi.utils.StringUtil; import javax.annotation.Resource; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; import java.util.Properties; @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { private Logger logger = LoggerFactory.getLogger(WebSecurityConfig.class); @Resource private AdminUserService adminUserService; private final String LOGIN_PROCESSING_URL = "/admin/api/login"; //图形验证码配置 @Bean public Producer captcha() { Properties properties = new Properties(); //图片的宽高 properties.setProperty("kaptcha.image.width", "150"); properties.setProperty("kaptcha.image.height", "50"); //字符集 properties.setProperty("kaptcha.textproducer.char.string", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"); //字符长度 properties.setProperty("kaptcha.textproducer.char.length", "4"); String color = "24,159,146"; //边框颜色 properties.setProperty("kaptcha.border.color", color); //字体颜色 properties.setProperty("kaptcha.textproducer.font.color", color); //干扰颜色 properties.setProperty("kaptcha.noise.color", color); Config config = new Config(properties); DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); defaultKaptcha.setConfig(config); return defaultKaptcha; } public class VerificationCodeException extends AuthenticationException { public VerificationCodeException() { super("图形验证码校验失败"); } } //验证码过滤器 class VerificationCodeFilter extends OncePerRequestFilter { private AuthenticationFailureHandler authenticationFailureHandler = new AuthenticationFailureHandler() { @Override public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { httpServletResponse.setContentType("application/json;charset=UTF-8"); JSONObject jsonObject = new JSONObject(); jsonObject.put("code", 11); jsonObject.put("msg", "验证码错误"); httpServletResponse.getWriter().print(jsonObject); } }; @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { if (!LOGIN_PROCESSING_URL.equalsIgnoreCase(httpServletRequest.getRequestURI())) { filterChain.doFilter(httpServletRequest, httpServletResponse); } else { try { verificationCode(httpServletRequest); filterChain.doFilter(httpServletRequest, httpServletResponse); } catch (VerificationCodeException e) { authenticationFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, e); } } } private void verificationCode(HttpServletRequest httpServletRequest) throws VerificationCodeException { String requestCode = httpServletRequest.getParameter("captcha"); HttpSession httpSession = httpServletRequest.getSession(); String captcha = httpSession.getAttribute("captcha") + ""; httpSession.removeAttribute("captcha"); if (StringUtil.isNullOrEmpty(captcha) || StringUtil.isNullOrEmpty(requestCode) || !captcha.equalsIgnoreCase(requestCode)) { throw new VerificationCodeException(); } } } @Override protected void configure(HttpSecurity http) throws Exception { http.headers().frameOptions().disable(); http.authorizeRequests() .antMatchers("/admin/api/captcha.jpg*").permitAll() .antMatchers("/admin/api/**", "/index.html").authenticated() .and() .formLogin() //自定义登录界面 .loginPage("/login.html") //处理登录逻辑的url .loginProcessingUrl(LOGIN_PROCESSING_URL) //登录成功后的跳转 .successHandler(new AuthenticationSuccessHandler() { @Override public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { logger.info("successHandler"); httpServletResponse.setContentType("application/json;charset=UTF-8"); JSONObject jsonObject = new JSONObject(); jsonObject.put("code", 0); jsonObject.put("msg", "登录成功"); httpServletResponse.getWriter().print(jsonObject); } }) //登录失败后的处理 .failureHandler(new AuthenticationFailureHandler() { @Override public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { logger.info("failureHandler"); httpServletResponse.setContentType("application/json;charset=UTF-8"); JSONObject jsonObject = new JSONObject(); jsonObject.put("code", 1); jsonObject.put("msg", e.getMessage()); httpServletResponse.getWriter().print(jsonObject); } }) .permitAll() .and() //退出登录 .logout().logoutUrl("/admin/api/logout").logoutSuccessHandler(new LogoutSuccessHandler() { @Override public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { logger.info("onLogoutSuccess"); httpServletResponse.getWriter().print(JsonUtil.loadTrueResult("")); } }) .and() .csrf().disable() .rememberMe().userDetailsService(new MyUserDetailsService()) .and().exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint()); http.addFilterBefore(new VerificationCodeFilter(), UsernamePasswordAuthenticationFilter.class); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(new MyAuthenticationProvider(new MyUserDetailsService(), new PasswordEncoder() { @Override public String encode(CharSequence charSequence) { return charSequence.toString(); } @Override public boolean matches(CharSequence charSequence, String s) { return s.equalsIgnoreCase(charSequence.toString()); } })); } class MyUserDetailsService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { AdminUser adminUser = null; if (!StringUtil.isNullOrEmpty(s)) { adminUser = adminUserService.selectByAccount(s); } else { throw new RuntimeException("请填写用户名"); } if (null != adminUser) { return adminUser; } else { throw new RuntimeException("该用户不存在"); } } } class MyAuthenticationProvider extends DaoAuthenticationProvider { public MyAuthenticationProvider(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) { this.setUserDetailsService(userDetailsService); this.setPasswordEncoder(passwordEncoder); } @Override protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException { if (usernamePasswordAuthenticationToken.getCredentials() == null) { throw new BadCredentialsException("密码不能为空"); } String pwd = StringUtil.Md5(usernamePasswordAuthenticationToken.getCredentials().toString()); if (!pwd.equalsIgnoreCase(userDetails.getPassword())) { throw new BadCredentialsException("密码错误"); } } } //自定义未授权返回 class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { String url = request.getRequestURI().toString(); if (url.contains("/admin/api/")) { response.setStatus(HttpStatus.UNAUTHORIZED.value()); } else { response.sendRedirect("/login.html"); } } } }