| | |
| | | package com.taoke.autopay.config; |
| | | |
| | | import com.google.code.kaptcha.Producer; |
| | | import com.google.code.kaptcha.impl.DefaultKaptcha; |
| | | import com.google.code.kaptcha.util.Config; |
| | | import com.taoke.autopay.entity.AdminUser; |
| | | import com.taoke.autopay.exception.VerificationCodeException; |
| | | import com.taoke.autopay.service.AdminUserService; |
| | | import net.sf.json.JSONObject; |
| | | 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.context.SecurityContext; |
| | | 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.util.AntPathMatcher; |
| | | 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 { |
| | | |
| | | @Resource |
| | | private AdminUserService adminUserService; |
| | | |
| | | private final String LOGIN_PROCESSING_URL = "/admin/api/login"; |
| | | |
| | | private final String LOGIN_PAGE_PATH = "/admin/login.html"; |
| | | |
| | | |
| | | private final static String[] STATIC_RESOURCE_PATHS = new String[]{ |
| | | "/**/*.html", "/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg", "/**/*.gif", "/**/*.xml", "/**/font/*", "/**/fonts/*" |
| | | "/*.html", "/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg", "/**/*.gif", "/**/*.xml", "/**/font/*", "/**/fonts/*", "/**/layui/**" |
| | | }; |
| | | |
| | | |
| | | /** |
| | | * @return com.google.code.kaptcha.Producer |
| | | * @author hxh |
| | | * @description 图形验证码配置 |
| | | * @date 0:29 2024/6/29 |
| | | **/ |
| | | @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 = "47,144,242"; |
| | | |
| | | //边框颜色 |
| | | 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; |
| | | } |
| | | |
| | | private Logger logger = LoggerFactory.getLogger(WebSecurityConfig.class); |
| | | |
| | |
| | | |
| | | @Override |
| | | protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { |
| | | if (!LOGIN_PROCESSING_URL.equalsIgnoreCase(httpServletRequest.getRequestURI())) { |
| | | //非登录接口 |
| | | String url = httpServletRequest.getRequestURI(); |
| | | //不验证静态资源 |
| | | AntPathMatcher pathMatcher = new AntPathMatcher(); |
| | | for (String resource : STATIC_RESOURCE_PATHS) { |
| | | if (pathMatcher.match(resource, url)) { |
| | | filterChain.doFilter(httpServletRequest, httpServletResponse); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | //尚未登录授权的就不需要验证权限了 |
| | | SecurityContext contextSession = (SecurityContext) httpServletRequest.getSession().getAttribute("SPRING_SECURITY_CONTEXT"); |
| | | |
| | | if (contextSession == null) { |
| | | filterChain.doFilter(httpServletRequest, httpServletResponse); |
| | | return; |
| | | } |
| | | Authentication authentication = contextSession.getAuthentication(); |
| | | if (authentication == null) { |
| | | filterChain.doFilter(httpServletRequest, httpServletResponse); |
| | | return; |
| | | } |
| | | AdminUser adminUser = (AdminUser) authentication.getPrincipal(); |
| | | if (adminUser == null) { |
| | | filterChain.doFilter(httpServletRequest, httpServletResponse); |
| | | return; |
| | | } |
| | | |
| | | //验证权限 |
| | | filterChain.doFilter(httpServletRequest, httpServletResponse); |
| | | |
| | | //无权限 |
| | | // authenticationFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, null); |
| | | } else { |
| | | //登录接口 |
| | | try { |
| | | verificationCode(httpServletRequest); |
| | | filterChain.doFilter(httpServletRequest, httpServletResponse); |
| | | } catch (VerificationCodeException e) { |
| | | verifyCodeFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | /** |
| | | * @return void |
| | | * @author hxh |
| | | * @description 验证验证码是否正确 |
| | | * @date 16:54 2022/5/19 |
| | | * @param: httpServletRequest |
| | | **/ |
| | | private void verificationCode(HttpServletRequest httpServletRequest) throws VerificationCodeException { |
| | | String requestCode = httpServletRequest.getParameter("code"); |
| | | 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("图形验证码错误"); |
| | | } |
| | | } |
| | | |
| | |
| | | protected void configure(HttpSecurity http) throws Exception { |
| | | http.headers().frameOptions().disable(); |
| | | http.authorizeRequests() |
| | | .antMatchers("*/**").permitAll().and().csrf().disable(); |
| | | // http.addFilterBefore(new PreRequestVerifyFilter(), UsernamePasswordAuthenticationFilter.class); |
| | | // 配置不需要鉴权的接口 |
| | | .antMatchers("/admin/api/captcha.jpg*", "/api/**", "/webapi/**","/credit/api/**","*/agentapi/**").permitAll() |
| | | //配置需要鉴权的接口 |
| | | .antMatchers("/admin/api/**", "/admin/index.html").authenticated() |
| | | .and() |
| | | .formLogin() |
| | | //自定义登录界面 |
| | | .loginPage(LOGIN_PAGE_PATH) |
| | | //处理登录逻辑的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 NotLoginAuthenticationEntryPoint()); |
| | | http.addFilterBefore(new PreRequestVerifyFilter(), UsernamePasswordAuthenticationFilter.class); |
| | | |
| | | |
| | | // http.addFilterBefore(new PreRequestVerifyFilter(), 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("密码错误"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * @author hxh |
| | | * @description 未登录的事件处理 |
| | | * @date 16:55 2022/5/19 |
| | | * @return |
| | | **/ |
| | | class NotLoginAuthenticationEntryPoint implements AuthenticationEntryPoint { |
| | | @Override |
| | | public void commence(HttpServletRequest request, HttpServletResponse response, |
| | | AuthenticationException authException) throws IOException, ServletException { |
| | | String url = request.getRequestURI(); |
| | | if (url.contains("/admin/api/")) { |
| | | response.setStatus(HttpStatus.UNAUTHORIZED.value()); |
| | | } else { |
| | | response.sendRedirect(LOGIN_PAGE_PATH); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | } |