# thyme-security **Repository Path**: thymeXd/thyme-security ## Basic Information - **Project Name**: thyme-security - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2019-05-31 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # thyme-security ## 介绍 Spring Security技术栈开发企业级认证与授权 学习笔记 ## 学习目录 [Spring Security基于表单的登录](#spring-security基于表单的登录) [使用Spring Social开发第三方登录](#使用spring-social开发第三方登录) ### Spring Security基于表单的登录 [实现Spring Security表单登录](#实现spring-security表单登录) [自定义用户认证逻辑](#自定义用户认证逻辑) [自定义登录页面](#自定义登录页面) [自定义登录成功处理](#自定义登录成功处理) [自定义登录失败处理](#自定义登录失败处理) [添加图片验证码](#添加图片验证码) [添加记住我功能](#添加记住我功能) ##### 实现Spring Security表单登录 ``` @Configuration public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { //登录方式 fomLogin表单登录 basic基本登录 http.formLogin() .and() //匹配请求 .authorizeRequests() //拦截所有 .anyRequest() .authenticated(); } } ``` 配置config注意报名,否则配置出现不生效 ##### 自定义用户认证逻辑 增加MyUserDetailService实现UserDetailsService方法处理用户登录 ``` @Component public class MyUserDetailService implements UserDetailsService { private Logger logger = LoggerFactory.getLogger(getClass()); //加密的时候应该在注册是时候做 @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { logger.info("登录用户名:"+ username); //根据用户名查找用户信息 //根据查找到的用户信息判断用户是否被冻结 String password = passwordEncoder.encode("123456"); return new User(username,password, true,true,true,true, AuthorityUtils.commaSeparatedStringToAuthorityList("admin")); } } ``` 在BrowserSecurityConfig类中增加Bean处理密码加密解密(可修改为自定义的加解密只需实现PasswordEncoder方法) ``` @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } ``` ##### 自定义登录页面 修改BrowserSecurityConfig类 ``` @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() .loginPage("/authentication/require") .loginProcessingUrl("/authentication/form") .and() .authorizeRequests() .antMatchers("/authentication/require",securityProperties.getBrowser().getLoginPage()).permitAll() .anyRequest() .authenticated() .and() .csrf().disable(); } ``` 增加controller请求 ``` /** * 当需要身份认证时,跳转到这里 * @param request * @param response * @return */ @RequestMapping("/authentication/require") @ResponseStatus(code = HttpStatus.UNAUTHORIZED) public SimpleResponse requireAuthentication(HttpServletRequest request, HttpServletResponse response) throws Exception{ SavedRequest savedRequest = requestCache.getRequest(request, response); if (savedRequest != null){ String targetUrl = savedRequest.getRedirectUrl(); logger.info("引发跳转的的请求是:{}",targetUrl); if (StringUtils.endsWithIgnoreCase(targetUrl,".html")){ redirectStrategy.sendRedirect(request,response,securityProperties.getBrowser().getLoginPage()); } } return new SimpleResponse("访问的服务需要身份认证,请引导用户到登录页"); } ``` ##### 自定义登录成功处理 增加自定义登录成功类 ``` @Component("thymeAuthenicationFailureHandler") public class ThymeAuthenicationFailureHandler implements AuthenticationFailureHandler { private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private ObjectMapper objectMapper; @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { logger.info("登录失败"); response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write(objectMapper.writeValueAsString(exception)); } } ``` BrowserSecurityConfig类增加配置 ``` @Autowired private AuthenticationSuccessHandler thymeAuthenicationSuccessHandler; http.formLogin() .loginPage("/authentication/require") .loginProcessingUrl("/authentication/form") .successHandler(thymeAuthenicationSuccessHandler) ``` ##### 自定义登录失败处理 增加自定义登录失败类 ``` @Component("thymeAuthenicationFailureHandler") public class ThymeAuthenicationFailureHandler implements AuthenticationFailureHandler { private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private ObjectMapper objectMapper; @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { logger.info("登录失败"); response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write(objectMapper.writeValueAsString(exception)); } } ``` BrowserSecurityConfig类增加配置 ``` @Autowired private AuthenticationFailureHandler thymeAuthenicationFailureHandler; http.formLogin() .loginPage("/authentication/require") .loginProcessingUrl("/authentication/form") .failureHandler(thymeAuthenicationFailureHandler) ``` ##### 添加图片验证码 1.添加验证码restful请求 ``` @RestController public class ValidateCodeController { public static final String SESSION_KEY = "SESSION_KEY_IMAGE_CODE"; private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); @GetMapping("/code/image") public void createCode(HttpServletRequest request, HttpServletResponse response) throws IOException { ImageCode imageCode = createImageCode(request); sessionStrategy.setAttribute(new ServletWebRequest(request),SESSION_KEY,imageCode); ImageIO.write(imageCode.getImage(),"JPEG",response.getOutputStream()); } private ImageCode createImageCode(HttpServletRequest request) { int width = 67; int height = 23; BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); Graphics g = image.getGraphics(); Random random = new Random(); g.setColor(getRandColor(200, 250)); g.fillRect(0, 0, width, height); g.setFont(new Font("Times New Roman", Font.ITALIC, 20)); g.setColor(getRandColor(160, 200)); for (int i = 0; i < 155; i++) { int x = random.nextInt(width); int y = random.nextInt(height); int xl = random.nextInt(12); int yl = random.nextInt(12); g.drawLine(x, y, x + xl, y + yl); } String sRand = ""; for (int i = 0; i < 4; i++) { String rand = String.valueOf(random.nextInt(10)); sRand += rand; g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110))); g.drawString(rand, 13 * i + 6, 16); } g.dispose(); return new ImageCode(image,sRand,60); } /** * 生成随机背景条纹 * * @param fc * @param bc * @return */ private Color getRandColor(int fc, int bc) { Random random = new Random(); if (fc > 255) { fc = 255; } if (bc > 255) { bc = 255; } int r = fc + random.nextInt(bc - fc); int g = fc + random.nextInt(bc - fc); int b = fc + random.nextInt(bc - fc); return new Color(r, g, b); } } ``` 2.前端页面修改 ```