前言
博客一
| # pom.xml |
| <dependencies> |
| <dependency> |
| <groupId>org.springframework.boot</groupId> |
| <artifactId>spring-boot-starter-web</artifactId> |
| </dependency> |
| <dependency> |
| <groupId>org.springframework.boot</groupId> |
| <artifactId>spring-boot-starter-security</artifactId> |
| </dependency> |
| </dependencies> |
| |
| # yml |
| server: |
| port: 8080 |
| |
| # 配置类配置用户名和密码 |
| @EnableWebSecurity |
| public class WebSecurityConfig extends WebSecurityConfigurerAdapter { |
| @Bean |
| public PasswordEncoder passwordEncoder() { |
| return new BCryptPasswordEncoder(); |
| } |
| @Override |
| protected void configure(AuthenticationManagerBuilder auth) throws Exception { |
| auth.inMemoryAuthentication().withUser("test").password(passwordEncoder().encode("123456")) |
| .authorities("admin"); |
| } |
| } |
| # 浏览器访问 http://localhost:8080/hello |
| |
| # 输入用户名和密码test:123456 |

博客二
- 参考
- 新建项目demo02,在demo01的基础上开发
| # 在WebSecurityConfig配置类中添加如下: |
| @Override |
| protected void configure(HttpSecurity http) throws Exception { |
| |
| FormLoginConfigurer<HttpSecurity> formLogin = http.formLogin(); |
| formLogin.loginPage(null); |
| formLogin.loginProcessingUrl(null); |
| formLogin.isCustomLoginPage(); |
| formLogin.passwordParameter(null); |
| formLogin.usernameParameter(null); |
| |
| formLogin.successForwardUrl(null); |
| formLogin.successHandler(null); |
| formLogin.defaultSuccessUrl(null); |
| |
| formLogin.failureForwardUrl(null); |
| formLogin.failureHandler(null); |
| formLogin.failureUrl(null); |
| |
| formLogin.permitAll(); |
| formLogin.permitAll(false); |
| |
| formLogin.disable(); |
| |
| formLogin.init(http); |
| formLogin.authenticationDetailsSource(null); |
| formLogin.addObjectPostProcessor(null); |
| formLogin.withObjectPostProcessor(null); |
| HttpSecurity and = formLogin.and(); |
| formLogin.setBuilder(and); |
| formLogin.configure(http); |
| |
| http.addFilter(null); |
| http.addFilterAfter(null, null); |
| http.addFilterAt(null, null); |
| |
| AnonymousConfigurer<HttpSecurity> anonymous = http.anonymous(); |
| http.anonymous(null); |
| |
| http.cors(); |
| http.cors(null); |
| http.csrf(); |
| http.csrf(null); |
| |
| http.headers(); |
| http.headers(null); |
| http.httpBasic(); |
| http.httpBasic(null); |
| |
| http.logout().addLogoutHandler(null); |
| http.logout(null); |
| |
| http.oauth2Client(); |
| http.oauth2Client(null); |
| http.oauth2Login(); |
| http.oauth2Login(null); |
| http.oauth2ResourceServer(); |
| http.oauth2ResourceServer(null); |
| |
| http.rememberMe(); |
| http.rememberMe(null); |
| |
| http.sessionManagement(); |
| http.sessionManagement(null); |
| |
| http.exceptionHandling(); |
| http.exceptionHandling(null); |
| http.userDetailsService(null); |
| http.authenticationProvider(null); |
| |
| http.antMatcher(null); |
| |
| http.apply(null); |
| |
| http.authorizeRequests().antMatchers("/**/*.js", "/**/*.css").permitAll().anyRequest().hasRole("admin"); |
| http.authorizeRequests(); |
| http.authorizeRequests(null); |
| |
| http.build(); |
| } |
- 表单登录选项: 表单请求成功处理器、失败处理器;与loginPage冲突,配置后,loginPage不生效
| formLogin.loginPage(null); |
| formLogin.loginProcessingUrl(null); |
| formLogin.isCustomLoginPage(); |
| formLogin.passwordParameter(null); |
| formLogin.usernameParameter(null); |
| |
| formLogin.successForwardUrl(null); |
| formLogin.successHandler(null); |
| formLogin.defaultSuccessUrl(null); |
| |
| formLogin.failureForwardUrl(null); |
| formLogin.failureHandler(null); |
| formLogin.failureUrl(null); |
| |
| formLogin.permitAll(); |
| formLogin.permitAll(false); |
| formLogin.disable(); |
| |
| formLogin.init(http); |
| formLogin.authenticationDetailsSource(null); |
| formLogin.addObjectPostProcessor(null); |
| formLogin.withObjectPostProcessor(null); |
| HttpSecurity and = formLogin.and(); |
| formLogin.setBuilder(and); |
| formLogin.configure(http); |
| |
| http.addFilter(null); |
| http.addFilterAfter(null, null); |
| http.addFilterAt(null, null); |
| # 匿名用户 |
| http.anonymous(); |
| # 跨域 |
| http.cors(); |
| http.cors(null); |
| # csrf |
| http.csrf(); |
| http.csrf(null); |
| # httpbasic,前后端分离时关闭 |
| http.httpBasic(); |
| http.httpBasic(null); |
| # 登出 |
| http.logout(); |
| http.logout(null); |
| http.logout().addLogoutHandler(null); |
| http.logout().disable(); |
| # 记住我 |
| http.rememberMe(); |
| http.rememberMe(null); |
| # session会话管理 |
| http.sessionManagement(); |
| http.sessionManagement(null); |
| http.sessionManagement().disable(); |
| # 认证处理器 |
| http.userDetailsService(null); |
| http.authenticationProvider(null); |
| # 鉴权管理 |
| http.authorizeRequests(); |
| http.authorizeRequests(null); |
| # 异常处理 |
| http.exceptionHandling(); |
| http.exceptionHandling(null); |
| http.oauth2Client(); |
| http.oauth2Client(null); |
| http.oauth2Login(); |
| http.oauth2Login(null); |
| http.oauth2ResourceServer(); |
| http.oauth2ResourceServer(null); |
| Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. |
| 2022-04-05 19:46:28.199 ERROR 22748 |
| |
| org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is java.lang.IllegalArgumentException: Pattern cannot be null or empty |
| at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:655) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE] |
博客三
- 参考
- 启动项目报错:Error creating bean with name 'xmlModelPlugin': Lookup method resolution failed
- 解决方案:注释swagger2相关的代码
- pom.xml
| <dependencies> |
| <dependency> |
| <groupId>org.springframework.boot</groupId> |
| <artifactId>spring-boot-starter-web</artifactId> |
| </dependency> |
| <dependency> |
| <groupId>org.springframework.boot</groupId> |
| <artifactId>spring-boot-starter-security</artifactId> |
| </dependency> |
| <dependency> |
| <groupId>com.alibaba</groupId> |
| <artifactId>fastjson</artifactId> |
| <version>1.2.78</version> |
| </dependency> |
| <dependency> |
| <groupId>org.projectlombok</groupId> |
| <artifactId>lombok</artifactId> |
| <optional>true</optional> |
| </dependency> |
| </dependencies> |
| @Data |
| public class Result { |
| private Integer code; |
| private String message; |
| private Result(Integer code, String messgae) { |
| this.code = code; |
| this.message = messgae; |
| } |
| public static Result success(String message) { |
| return new Result(200, message); |
| } |
| public static Result result(Integer code, String messgae) { |
| return new Result(code, messgae); |
| } |
| } |
| @EnableWebSecurity |
| public class WebSecurityConfig extends WebSecurityConfigurerAdapter { |
| |
| private static final String[] EXCLUDE_URLS = { "/**/*.js", "/**/*.css", "/**/*.jpg", "/**/*.png", "/**/*.gif", |
| "/v2/**", "/errors", "/error", "/favicon.ico", "/swagger-ui.html/**", "/swagger-ui/**", "/webjars/**", |
| "/swagger-resources/**", "/auth/login" }; |
| @Autowired |
| private AuthenticationSuccessHandler successHandler; |
| @Autowired |
| private AuthenticationFailureHandler failureHandler; |
| @Autowired |
| AccessDeniedHandler deniedHandler; |
| @Autowired |
| AuthenticationEntryPoint entryPoint; |
| |
| @Bean |
| public PasswordEncoder passwordEncoder() { |
| return new BCryptPasswordEncoder(); |
| } |
| |
| @Override |
| protected void configure(AuthenticationManagerBuilder auth) throws Exception { |
| auth.inMemoryAuthentication().withUser("test").password(passwordEncoder().encode("123456")) |
| .authorities("admin"); |
| } |
| @Override |
| protected void configure(HttpSecurity http) throws Exception { |
| |
| http.exceptionHandling().accessDeniedHandler(deniedHandler).authenticationEntryPoint(entryPoint); |
| |
| http.authorizeRequests().antMatchers(EXCLUDE_URLS).permitAll(); |
| |
| FormLoginConfigurer<HttpSecurity> formLogin = http.formLogin(); |
| |
| formLogin.successHandler(successHandler).failureHandler(failureHandler); |
| |
| formLogin.loginProcessingUrl("/auth/login"); |
| |
| http.csrf().disable(); |
| } |
| } |
| @Component |
| public class DeniedHandler implements AccessDeniedHandler { |
| @SuppressWarnings("deprecation") |
| @Override |
| public void handle(HttpServletRequest request, HttpServletResponse response, |
| AccessDeniedException accessDeniedException) throws IOException, ServletException { |
| String error = "请求Url:" + request.getRequestURI() + " 鉴权失败:" + accessDeniedException.getMessage(); |
| response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); |
| PrintWriter writer = response.getWriter(); |
| writer.print(JSON.toJSONString(Result.result(HttpStatus.UNAUTHORIZED.value(), error))); |
| writer.flush(); |
| writer.close(); |
| } |
| } |
| @Component |
| public class EntryPoint implements AuthenticationEntryPoint { |
| @SuppressWarnings("deprecation") |
| @Override |
| public void commence(HttpServletRequest request, HttpServletResponse response, |
| AuthenticationException authException) throws IOException, ServletException { |
| String error = "请求Url:" + request.getRequestURI() + " 认证失败:" + authException.getMessage(); |
| response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); |
| PrintWriter writer = response.getWriter(); |
| writer.print(JSON.toJSONString(Result.result(HttpStatus.UNAUTHORIZED.value(), error))); |
| writer.flush(); |
| writer.close(); |
| } |
| } |
| @Component |
| @Slf4j |
| public class SuccessHandler implements AuthenticationSuccessHandler { |
| @SuppressWarnings("deprecation") |
| @Override |
| public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, |
| Authentication authentication) throws IOException, ServletException { |
| response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); |
| log.info("登录成功:{}", authentication.getPrincipal()); |
| PrintWriter writer = response.getWriter(); |
| writer.print(JSON.toJSONString(Result.success(authentication.getPrincipal().toString()))); |
| writer.flush(); |
| writer.close(); |
| } |
| } |
| @Component |
| public class FailureHandler implements AuthenticationFailureHandler { |
| private Logger log = LoggerFactory.getLogger(getClass()); |
| @SuppressWarnings("deprecation") |
| @Override |
| public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, |
| AuthenticationException exception) throws IOException, ServletException { |
| log.info("登录失败,{}", exception.getMessage()); |
| response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); |
| PrintWriter writer = response.getWriter(); |
| writer.print(JSON.toJSONString(Result.result(400, exception.getMessage()))); |
| writer.flush(); |
| writer.close(); |
| } |
| } |
| @RestController |
| public class LoginController { |
| @PostMapping("/auth/login") |
| public void login(@RequestParam(name = "username", required = true) String username, |
| @RequestParam(name = "password", required = true) String password) { |
| } |
| } |
- 测试

博客五

| 1. 向手机发送手机验证码,使用第三方短信平台 SDK 发送,如: 阿里云短信服务(阿里大于) |
| 2. 登录表单输入短信验证码 |
| 3. 使用自定义过滤器 MobileValidateFilter |
| 4. 当验证码校验通过后,进入自定义手机认证过滤器 MobileAuthenticationFilter 校验手机号是否存在 |
| 5. 自定义 MobileAuthenticationToken 提供给 MobileAuthenticationFilter |
| 6. 自定义 MobileAuthenticationProvider 提供给 ProviderManager 处理 |
| 7. 创建针对手机号查询用户信息的 MobileUserDetailsService ,交给 MobileAuthenticationProvider |
| 8. 自定义 MobileAuthenticationConfig 配置类将上面组件连接起来,添加到容器中 |
| 9. 将 MobileAuthenticationConfig 添加到 SpringSecurityConfig 安全配置的过滤器链上 |
- UsernamePasswordAuthenticationProvider
| @Slf4j |
| public class UsernamePasswordAuthenticationProvider implements AuthenticationProvider { |
| |
| @Getter |
| @Setter |
| private UserDetailsService userDetailsService; |
| @Autowired |
| private PasswordEncoder passwordEncoder; |
| |
| public UsernamePasswordAuthenticationProvider(UserDetailsService userDetailsService) { |
| super(); |
| this.userDetailsService = userDetailsService; |
| } |
| |
| @Override |
| public Authentication authenticate(Authentication authentication) throws AuthenticationException { |
| |
| String username = (String) authentication.getPrincipal(); |
| |
| String password = (String) authentication.getCredentials(); |
| UserDetails userDetails; |
| try { |
| userDetails = userDetailsService.loadUserByUsername(username); |
| } catch (Exception e) { |
| |
| throw new AuthenticationServiceException(e.getMessage()); |
| } |
| if (!passwordEncoder.matches(password, userDetails.getPassword())) { |
| log.info("当前登录人:{},当前登录密码:{}", username, password); |
| throw new BadCredentialsException("用户密码不正确"); |
| } |
| return new UsernamePasswordAuthenticationToken(username, null, userDetails.getAuthorities()); |
| } |
| |
| @Override |
| public boolean supports(Class<?> authentication) { |
| |
| return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); |
| } |
| } |
| @Configuration |
| public class SecurityConfig { |
| |
| static final List<UserEntity> USER_LIST = new ArrayList<>(); |
| |
| static { |
| for (int i = 1; i < 6; i++) { |
| UserEntity userEntity = new UserEntity(); |
| userEntity.setId(i); |
| userEntity.setName("测试人员" + i); |
| userEntity.setUsername("ceshi_" + i); |
| |
| userEntity.setPassword("$2a$10$D1q09WtH./yTfFTh35n0k.o6yZIXwxIW1/ex6/EjYTF7EiNxXyF7m"); |
| userEntity.setEmail("100" + i + "@qq.com"); |
| userEntity.setPhone("186xxxx351" + i); |
| USER_LIST.add(userEntity); |
| } |
| } |
| |
| |
| @Bean |
| public UserDetailsService usernamePasswordUserDetails() { |
| return new UserDetailsService() { |
| @Override |
| public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { |
| UserEntity user = null; |
| for (UserEntity userEntity : USER_LIST) { |
| if (username.equals(userEntity.getUsername()) || username.equals(userEntity.getPhone()) |
| || username.equals(userEntity.getEmail())) { |
| user = userEntity; |
| } |
| } |
| if (user != null) { |
| return new SystemUserDetails(user.getUsername(), user.getPassword(), user, null); |
| } |
| throw new UsernameNotFoundException("用户未注册,请先注册"); |
| } |
| }; |
| } |
| |
| @Bean |
| public AuthenticationProvider usernamePasswordAuthenticationProvider() { |
| return new UsernamePasswordAuthenticationProvider(usernamePasswordUserDetails()); |
| } |
| |
| } |
| curl -X POST "http://localhost:8080/auth/login?username=ceshi_1&password=123456" -H "accept: */*" |
| curl -X POST "http://localhost:8080/auth/login?username=1001@qq.com&password=123456" -H "accept: */*" |
| curl -X POST "http://localhost:8080/auth/login?username=186xxxx3511&password=123456" -H "accept: */*" |
博客六
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通