阿里云网站域名证书icp备案 网站服务内容

张小明 2025/12/30 18:31:37
阿里云网站域名证书,icp备案 网站服务内容,小众但惊艳的公司名称,在线网站建设询问报价认证--JSON课程计划登录成功/失败之后返回json字符串未登录错误提示退出登录json提示获取个人信息/修改个人信息JSON登录手机号验证码登录一、登录成功/失败返回JSON1、修改第一个版本的代码直接编写返回的json字符串Configuration EnableWebSecurity public class SecurityCon…认证--JSON课程计划登录成功/失败之后返回json字符串未登录错误提示退出登录json提示获取个人信息/修改个人信息JSON登录手机号验证码登录一、登录成功/失败返回JSON1、修改第一个版本的代码直接编写返回的json字符串Configuration EnableWebSecurity public class SecurityConfig { ​ Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { //http对象支持链式调用 //关闭csrf 跨域请求伪造的控制 http.csrf(csrf - csrf.disable()); http.authorizeHttpRequests( auth - auth.requestMatchers(/loginpage.html, /login/**) .permitAll() .anyRequest().authenticated() //其他页面要登录之后才能访问 );//放过登录接口以及静态页面 // ↓配置表单提交 http.formLogin(form - { form.loginPage(/loginpage.html) //自定义登录页面的路径 .loginProcessingUrl(/javasmlogin) //表单提交的路径 .usernameParameter(uname) //自定义用户名的参数名默认是username .passwordParameter(pwd) //Authentication 是 UsernamePasswordAuthenticationToken-- principal实际的值UserDetails .successHandler(new AuthenticationSuccessHandler() { Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { response.setContentType(application/json;charsetutf-8); R ok R.ok(authentication); //写出去 PrintWriter writer response.getWriter(); writer.write(JSON.toJSONString(ok)); writer.flush(); writer.close(); } }) //AuthenticationException 包含了 登录失败之后的 异常信息 .failureHandler(new AuthenticationFailureHandler() { Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { response.setContentType(application/json;charsetutf-8); R error R.error(exception.getMessage()); //写出去 PrintWriter writer response.getWriter(); writer.write(JSON.toJSONString(error)); writer.flush(); writer.close(); } }) .permitAll(); //以上提到的路径都放行 }); //注销登录 http.logout(logout - logout .logoutUrl(/logout) .logoutSuccessUrl(/loginpage.html)//注销成功之后跳转的路径 .permitAll() ); return http.build(); ​ } ​ Bean public PasswordEncoder passwordEncoder() { //指定加密算法 return new BCryptPasswordEncoder(); } }2、优化代码Configuration EnableWebSecurity public class SecurityConfig { ​ Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { //http对象支持链式调用 //关闭csrf 跨域请求伪造的控制 http.csrf(csrf - csrf.disable()); http.authorizeHttpRequests( auth - auth.requestMatchers(/loginpage.html, /login/**) .permitAll() .anyRequest().authenticated() //其他页面要登录之后才能访问 );//放过登录接口以及静态页面 // ↓配置表单提交 http.formLogin(form - { form.loginPage(/loginpage.html) //自定义登录页面的路径 .loginProcessingUrl(/javasmlogin) //表单提交的路径 .usernameParameter(uname) //自定义用户名的参数名默认是username .passwordParameter(pwd) //Authentication 是 UsernamePasswordAuthenticationToken-- principal实际的值UserDetails .successHandler((request, response, authentication) - createSuccessJson(response,authentication) ) //AuthenticationException 包含了 登录失败之后的 异常信息 .failureHandler((request, response, exception) - createFailJson(response,exception) ) .permitAll(); //以上提到的路径都放行 }); //注销登录 http.logout(logout - logout .logoutUrl(/logout) .logoutSuccessUrl(/loginpage.html)//注销成功之后跳转的路径 .permitAll() ); return http.build(); ​ } ​ Bean public PasswordEncoder passwordEncoder() { //指定加密算法 return new BCryptPasswordEncoder(); } ​ private void createSuccessJson(HttpServletResponse response,Object object){ R ok R.ok(object); createJson(response,ok); } ​ private void createFailJson(HttpServletResponse response,AuthenticationException e){ R error R.error(e.getMessage()); createJson(response,error); } ​ private void createJson(HttpServletResponse response,R r){ try { response.setContentType(application/json;charsetutf-8); //写出去 PrintWriter writer response.getWriter(); writer.write(JSON.toJSONString(r)); writer.flush(); writer.close(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } }二、配置未登录异常信息的处理未配置的情况下会拦截请求跳转到登录页面http.exceptionHandling().authenticationEntryPoint((request,response,e)- createFailJson(response,当前用户未登录请先登录再访问));三、退出登录Configuration EnableWebSecurity public class SecurityConfig { ​ Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { //http对象支持链式调用 //关闭csrf 跨域请求伪造的控制 http.csrf(csrf - csrf.disable()); http.authorizeHttpRequests( auth - auth.requestMatchers(/loginpage.html, /login/**) .permitAll() .anyRequest().authenticated() //其他页面要登录之后才能访问 );//放过登录接口以及静态页面 // ↓配置表单提交 http.formLogin(form - { form.loginPage(/loginpage.html) //自定义登录页面的路径 .loginProcessingUrl(/javasmlogin) //表单提交的路径 .usernameParameter(uname) //自定义用户名的参数名默认是username .passwordParameter(pwd) //Authentication 是 UsernamePasswordAuthenticationToken-- principal实际的值UserDetails .successHandler((request, response, authentication) - createSuccessJson(response,authentication) ) //AuthenticationException 包含了 登录失败之后的 异常信息 .failureHandler((request, response, exception) - createFailJson(response,exception) ) .permitAll(); //以上提到的路径都放行 }); //注销登录 http.logout(logout - logout .logoutUrl(/logout) //退出登录的时候返回用户信息 .logoutSuccessHandler((r,response,a)-createSuccessJson(response,退出登录成功)) .permitAll() ); //未登录异常提示 http.exceptionHandling().authenticationEntryPoint((request,response,e)- createFailJson(response,当前用户未登录请先登录再访问)); return http.build(); ​ } ​ Bean public PasswordEncoder passwordEncoder() { //指定加密算法 return new BCryptPasswordEncoder(); } ​ private void createSuccessJson(HttpServletResponse response,Object object){ R ok R.ok(object); createJson(response,ok); } ​ private void createFailJson(HttpServletResponse response,AuthenticationException e){ R error R.error(e.getMessage()); createJson(response,error); } private void createFailJson(HttpServletResponse response,String e){ R error R.error(e); createJson(response,error); } ​ private void createJson(HttpServletResponse response,R r){ try { response.setContentType(application/json;charsetutf-8); //如果想修改返回的状态码可以这么修改 //response.setStatus(r.getCode()); //写出去 PrintWriter writer response.getWriter(); writer.write(JSON.toJSONString(r)); writer.flush(); writer.close(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); }四、获取当前登录的用户信息已经登录之后获取当前登录的用户信息GetMapping(/my) public R queryMyUser(){ LoginUserDetails loginUserDetails loginService.getLoginUser(); return R.ok(loginUserDetails); }Override public LoginUserDetails getLoginUser() { //查询已经登录的用户信息 //获取Security上下文对象 SecurityContext context SecurityContextHolder.getContext(); //从上下文对象中获取用户信息。UsernamePasswordAuthenticationToken Authentication authentication context.getAuthentication(); if (authentication null){ throw new JavasmException(ExceptionEnum.Not_Login); } //principal 未登录成功之前在UsernamePasswordAuthenticationFilter中赋值是用户名 //登录成功之后在DaoAuthenticationProvider中赋值是UserDetails Object principal authentication.getPrincipal(); if (principal instanceof LoginUserDetails){ LoginUserDetails loginUserDetails (LoginUserDetails) principal; return loginUserDetails; }else { throw new JavasmException(ExceptionEnum.Not_Login); } }五、修改当前登录的用户信息PutMapping(/update/loginuser) public R updateLoginUser(AdminUser adminUser){ loginService.updateLoginUser(adminUser); return R.ok(); }Override public void updateLoginUser(AdminUser adminUser) { //修改数据 //先获取个人信息当前登录的用户数据 LoginUserDetails loginUser getLoginUser(); if (loginUser ! null){ AdminUser loginAdminUser loginUser.getAdminUser(); Integer uid loginAdminUser.getUid(); adminUser.setUid(uid); //密码 if (!StringUtils.isEmpty(adminUser.getPassword())){ //如果传了 密码密码需要加密之后再保存到数据库 String encodePassword passwordEncoder.encode(adminUser.getPassword()); adminUser.setPassword(encodePassword); } //存储成功 adminUser.updateById(); //上面只是修改了数据库的信息同步Security中的用户信息 //更新的对象 adminuser中不一定包括所有的字段从数据库中查询出最新的数据同步到Security中 AdminUser newAdminUser adminUserService.getById(uid); LoginUserDetails loginUserDetails new LoginUserDetails(newAdminUser); UsernamePasswordAuthenticationToken authentication UsernamePasswordAuthenticationToken.authenticated( loginUserDetails, //最新的登录用户信息 newAdminUser.getPassword(), // 最新的密码 loginUser.getAuthorities() //授权列表 ); //获取上下文对象--并把新的Authentication对象存储起来 SecurityContextHolder.getContext().setAuthentication(authentication); } ​ }六、JSON格式登录1、普通版本确认一下登录接口的名字和数据格式/jsonlogin{ username:test11, password:123 }这个请求方式本质上依然是用户名和密码登录唯一改变的是获取用户名和密码的方式1.1 新建一个Filterpublic class JsonFilter extends UsernamePasswordAuthenticationFilter { public static final String SPRING_SECURITY_JSON_USERNAME_KEY username; public static final String SPRING_SECURITY_JSON_PASSWORD_KEY password; SneakyThrows Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (!request.getMethod().equals(POST)) { throw new AuthenticationServiceException(Authentication method not supported: request.getMethod()); } else if (!request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)){ throw new AuthenticationServiceException(请求的类型不对应该是JSON格式); } else { //request对象中可以获取用户名和密码 ServletInputStream inputStream request.getInputStream(); //字节流转成字符流 InputStreamReader streamReader new InputStreamReader(inputStream); //转成字符流 BufferedReader bufferedReader new BufferedReader(streamReader); //存储字符的StringBuffer StringBuffer jsonBuffer new StringBuffer(); String line; while ((line bufferedReader.readLine()) ! null){ jsonBuffer.append(line); } //用户传入的json字符串 String json jsonBuffer.toString().trim(); if (StringUtils.isEmpty(json)){ throw new AuthenticationServiceException(参数为空); } //把数据转成map MapString,String map JSONObject.parseObject(json, Map.class); String username map.get(SPRING_SECURITY_JSON_USERNAME_KEY); username username ! null ? username.trim() : ; String password map.get(SPRING_SECURITY_JSON_PASSWORD_KEY); password password ! null ? password : ; UsernamePasswordAuthenticationToken authRequest UsernamePasswordAuthenticationToken.unauthenticated(username, password); this.setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } } }1.2 把JsonFilter 配置到过滤器链中修改配置类Configuration EnableWebSecurity public class SecurityConfig { //****************JSON登录--开始****************// Resource(name usernameLoginUserDetailsService) UserDetailsService userDetailsService; Bean public DaoAuthenticationProvider jsonProvider() { DaoAuthenticationProvider authenticationProvider new DaoAuthenticationProvider(); //配置 由哪个UserDetailsService负责查询用户信息UserDetails authenticationProvider.setUserDetailsService(userDetailsService); //配置密码的加密方式 authenticationProvider.setPasswordEncoder(passwordEncoder()); return authenticationProvider; } //JSON等于专属的AuthenticationManager Bean public AuthenticationManager jsonAuthenticationManager() { return new ProviderManager(List.of(jsonProvider())); } //配置JsonFilter public JsonFilter jsonFilter() { JsonFilter jsonFilter new JsonFilter(); //配置 AuthenticationManager jsonFilter.setAuthenticationManager(jsonAuthenticationManager()); //json登录成功之后的显示 jsonFilter.setAuthenticationSuccessHandler(this::createSuccessJson); //json登录失败之后 jsonFilter.setAuthenticationFailureHandler( (r, response, e) - createFailJson(response, e) ); //配置json登录的路径 jsonFilter.setFilterProcessesUrl(/jsonlogin); return jsonFilter; } Bean public SecurityContextRepository securityContextRepository() { return new HttpSessionSecurityContextRepository(); } //****************JSON登录--结束****************// Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.securityContext(context - context.securityContextRepository(securityContextRepository())); //因为当前json登录功能和用户名密码登录功能类似 // 所以把jsonfilter放到UsernamePasswordAuthenticaitonFilter相同的位置 http.addFilterAt(jsonFilter(), UsernamePasswordAuthenticationFilter.class); //关闭csrf 跨域请求伪造的控制 http.csrf(csrf - csrf.disable()); http.authorizeHttpRequests( auth - auth.requestMatchers(/loginpage.html, /login/**) .permitAll() .anyRequest().authenticated() //其他页面要登录之后才能访问 );//放过登录接口以及静态页面 // ↓配置表单提交 http.formLogin(form - { form.loginPage(/loginpage.html) //自定义登录页面的路径 .loginProcessingUrl(/javasmlogin) //表单提交的路径 .usernameParameter(uname) //自定义用户名的参数名默认是username .passwordParameter(pwd) //Authentication 是 UsernamePasswordAuthenticationToken-- principal实际的值UserDetails .successHandler(this::createSuccessJson) //AuthenticationException 包含了 登录失败之后的 异常信息 .failureHandler((request, response, exception) - createFailJson(response, exception) ) .permitAll(); //以上提到的路径都放行 }); //注销登录 http.logout(logout - logout .logoutUrl(/logout) //退出登录的时候返回用户信息 .logoutSuccessHandler((r, response, a) - createSuccessJson(response, 退出登录成功)) .permitAll() ); //未登录异常提示 http.exceptionHandling().authenticationEntryPoint((request, response, e) - createFailJson(response, 当前用户未登录请先登录再访问)); return http.build(); } Bean public PasswordEncoder passwordEncoder() { //指定加密算法 return new BCryptPasswordEncoder(); } private void createSuccessJson(HttpServletRequest request,HttpServletResponse response, Authentication authentication) { SecurityContextHolderStrategy strategy SecurityContextHolder.getContextHolderStrategy(); strategy.getContext().setAuthentication(authentication); securityContextRepository().saveContext(strategy.getContext(), request, response); createSuccessJson(response,authentication); } private void createSuccessJson(HttpServletResponse response, Object object) { R ok R.ok(object); createJson(response, ok); } private void createFailJson(HttpServletResponse response, AuthenticationException e) { R error R.error(e.getMessage()); createJson(response, error); } private void createFailJson(HttpServletResponse response, String e) { R error R.error(e); createJson(response, error); } private void createJson(HttpServletResponse response, R r) { try { response.setContentType(application/json;charsetutf-8); //如果想修改返回的状态码可以这么修改 //response.setStatus(r.getCode()); //写出去 PrintWriter writer response.getWriter(); writer.write(JSON.toJSONString(r)); writer.flush(); writer.close(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } }2、简单版2.1 正常的ControllerPostMapping(/json) public R doJsonLogin(RequestBody AdminUser adminUser){ ParameterUtils.checkParameter(adminUser); ParameterUtils.checkParameter(adminUser.getUsername(),adminUser.getPassword()); //import org.springframework.security.core.Authentication; Authentication authentication loginService.doJsonLogin(adminUser); return R.ok(authentication); }2.2 正常的ServiceResource HttpSession httpSession; Resource HttpServletRequest request; Resource HttpServletResponse response; Resource SecurityContextRepository securityContextRepository; Override public Authentication doJsonLogin(AdminUser adminUser) { //获取用户名和密码 String username adminUser.getUsername(); String password adminUser.getPassword(); //根据用户名 查询用户信息 AdminUser loginAdminUser adminUserService.getByUsername(username); if (loginAdminUser null) { throw new JavasmException(ExceptionEnum.User_Not_Found); } //判断 密码是否正确 if (!this.passwordEncoder.matches(password, loginAdminUser.getPassword())) { throw new JavasmException(ExceptionEnum.Password_Error); } //登录成功了--以下的代码不能放入多线程中 //Security已经做了线程安全的设置如果使用子线程存储数据是无法获取主线程中的对象的 UserDetails userDetails new LoginUserDetails(loginAdminUser); //创建一个新的 UsernamePasswordAuthenticationToken UsernamePasswordAuthenticationToken authenticated UsernamePasswordAuthenticationToken.authenticated( userDetails, loginAdminUser.getPassword(), userDetails.getAuthorities() ); //登录成功的标志存储到上下文对象中 //SecurityContextHolder.getContext().setAuthentication(authenticated); SecurityContextHolderStrategy strategy SecurityContextHolder.getContextHolderStrategy(); strategy.getContext().setAuthentication(authenticated); securityContextRepository.saveContext(strategy.getContext(), request, response); return authenticated; }七、图片验证码在json登录的案例中添加图片验证码1、引入第三方依赖!--图片验证码-- dependency groupIdcom.github.whvcse/groupId artifactIdeasy-captcha/artifactId version1.6.2/version /dependency !--手动引入Nashorn Javascript引擎-- dependency groupIdorg.openjdk.nashorn/groupId artifactIdnashorn-core/artifactId version15.4/version /dependency2、生成图片接口Resource HttpServletResponse response; Resource HttpSession httpSession; GetMapping(/imgcode) public void createImageCode() throws IOException { //ArithmeticCaptcha 算术验证码 //SpecCaptcha 英文验证码 // ChineseCaptcha 中文验证码 // GifCaptcha 动态图片 ArithmeticCaptcha captcha new ArithmeticCaptcha(150,50); //SpecCaptcha captcha new SpecCaptcha(150,50); //ChineseCaptcha captcha new ChineseCaptcha(150,50); //GifCaptcha captcha new GifCaptcha(150,50); //几个数字的算术题 captcha.setLen(2); //获取验证码的结果--算术题的答案 String code captcha.text(); //验证码的内存存储到Session对象中等待调用 httpSession.setAttribute(img_code,code); //输出图片 captcha.out(response.getOutputStream()); }3、修改原有登录代码public class JsonFilter extends UsernamePasswordAuthenticationFilter { public static final String SPRING_SECURITY_JSON_USERNAME_KEY username; public static final String SPRING_SECURITY_JSON_PASSWORD_KEY password; SneakyThrows Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (!request.getMethod().equals(POST)) { throw new AuthenticationServiceException(Authentication method not supported: request.getMethod()); } else if (!request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) { throw new AuthenticationServiceException(请求的类型不对应该是JSON格式); } else { //request对象中可以获取用户名和密码 ServletInputStream inputStream request.getInputStream(); //字节流转成字符流 InputStreamReader streamReader new InputStreamReader(inputStream); //转成字符流 BufferedReader bufferedReader new BufferedReader(streamReader); //存储字符的StringBuffer StringBuffer jsonBuffer new StringBuffer(); String line; while ((line bufferedReader.readLine()) ! null) { jsonBuffer.append(line); } //用户传入的json字符串 String json jsonBuffer.toString().trim(); if (StringUtils.isEmpty(json)) { throw new AuthenticationServiceException(参数为空); } //把数据转成map MapString, String map JSONObject.parseObject(json, Map.class); String code map.get(code); Object imgCode request.getSession().getAttribute(img_code); if (code.isEmpty() || imgCode null || imgCode.toString().isEmpty() || !code.equals(imgCode)) { throw new AuthenticationServiceException(验证码错误); } String username map.get(SPRING_SECURITY_JSON_USERNAME_KEY); username username ! null ? username.trim() : ; String password map.get(SPRING_SECURITY_JSON_PASSWORD_KEY); password password ! null ? password : ; UsernamePasswordAuthenticationToken authRequest UsernamePasswordAuthenticationToken.unauthenticated(username, password); this.setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } } }简单版Resource HttpSession httpSession; Resource HttpServletRequest request; Resource HttpServletResponse response; Resource SecurityContextRepository securityContextRepository; Override public Authentication doJsonLogin(AdminUser adminUser) { String code adminUser.getCode(); Object imgCode httpSession.getAttribute(img_code); if (code.isEmpty() || imgCode null || imgCode.toString().isEmpty() || !code.equals(imgCode)) { throw new JavasmException(ExceptionEnum.Code_Error); } //获取用户名和密码 String username adminUser.getUsername(); String password adminUser.getPassword(); //根据用户名 查询用户信息 AdminUser loginAdminUser adminUserService.getByUsername(username); if (loginAdminUser null) { throw new JavasmException(ExceptionEnum.User_Not_Found); } //判断 密码是否正确 if (!this.passwordEncoder.matches(password, loginAdminUser.getPassword())) { throw new JavasmException(ExceptionEnum.Password_Error); } //登录成功了--以下的代码不能放入多线程中 //Security已经做了线程安全的设置如果使用子线程存储数据是无法获取主线程中的对象的 UserDetails userDetails new LoginUserDetails(loginAdminUser); //创建一个新的 UsernamePasswordAuthenticationToken UsernamePasswordAuthenticationToken authenticated UsernamePasswordAuthenticationToken.authenticated( userDetails, loginAdminUser.getPassword(), userDetails.getAuthorities() ); //登录成功的标志存储到上下文对象中 //SecurityContextHolder.getContext().setAuthentication(authenticated); SecurityContextHolderStrategy strategy SecurityContextHolder.getContextHolderStrategy(); strategy.getContext().setAuthentication(authenticated); securityContextRepository.saveContext(strategy.getContext(), request, response); return authenticated; }TableField(exist false) private String code;八、手机号验证码1、发送验证码GetMapping(/phone/code) public R sendPhoneCode(String phone){ String code loginService.sendPhoneCode(phone); return R.ok(code); }Resource RedisTemplateString,Object redisTemplate; Override public String sendPhoneCode(String phone) { //生成一个随机数 String code RandomUtil.getCode(4); //TODO:发送到手机 //值存入Redis String key String.format(RedisKeys.AdminUserPhone,phone); redisTemplate.opsForValue().set(key,code,10, TimeUnit.MINUTES); return code; }2、模仿用户名密码登录写一套手机号验证码登录FilterAuthenticationProviderUserDetailsService修改配置文件/phoneLogin{ phone:11111, code:1234 }3、PhoneFilter用来接收参数public class PhoneFilter extends AbstractAuthenticationProcessingFilter { public static final String SPRING_SECURITY_PHONE_KEY phone; public static final String SPRING_SECURITY_CODE_KEY code; private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER new AntPathRequestMatcher(/phoneLogin, POST); public PhoneFilter() { super(DEFAULT_ANT_PATH_REQUEST_MATCHER); } public PhoneFilter(AuthenticationManager authenticationManager) { super(DEFAULT_ANT_PATH_REQUEST_MATCHER, authenticationManager); } Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { if (!request.getMethod().equals(POST)) { throw new AuthenticationServiceException(Authentication method not supported: request.getMethod()); }else if (!request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) { throw new AuthenticationServiceException(请求的类型不对应该是JSON格式); } else { //获取json参数 MapString, String map RequestJsonUtil.getRequestJson(request); String phone map.get(SPRING_SECURITY_PHONE_KEY); phone phone ! null ? phone.trim() : ; String code map.get(SPRING_SECURITY_CODE_KEY); code code ! null ? code : ; PhoneAuthenticationToken authRequest PhoneAuthenticationToken.unauthenticated(phone,code); this.setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } } protected void setDetails(HttpServletRequest request, PhoneAuthenticationToken authRequest) { authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request)); } }4、PhoneAuthenticationTokenpublic class PhoneAuthenticationToken extends AbstractAuthenticationToken { Getter private String phone; Getter private String code; private UserDetails userDetails; //未登录成功之前调用的 public PhoneAuthenticationToken(String phone, String code) { super((Collection)null); this.phone phone; this.code code; this.setAuthenticated(false); } //登录成功之后用来向Filter 回值的 public PhoneAuthenticationToken(UserDetails userDetails) { super(userDetails.getAuthorities()); this.userDetails userDetails; this.code userDetails.getPassword(); //保证这里 super.setAuthenticated(true); } public static PhoneAuthenticationToken unauthenticated(String phone, String code) { return new PhoneAuthenticationToken(phone, code); } public static PhoneAuthenticationToken authenticated(UserDetails userDetails) { return new PhoneAuthenticationToken(userDetails); } Override public Object getCredentials() { return this.code; } Override public Object getPrincipal() { return this.userDetails; } }5、PhoneProviderComponent public class PhoneProvider implements AuthenticationProvider { Resource RedisTemplateString,String redisTemplate; Resource(name phoneLoginUserDetailsService) UserDetailsService userDetailsService; //Authentication → PhoneAuthenticationToken Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { PhoneAuthenticationToken phoneAuthenticationToken (PhoneAuthenticationToken) authentication; //获取手机号 String phone phoneAuthenticationToken.getPhone(); //获取验证码 String code phoneAuthenticationToken.getCode(); //校验 验证码是否正确 String key String.format(RedisKeys.AdminUserPhone,phone); //从Redis中获取正确的验证码 String realCode redisTemplate.opsForValue().get(key); if (realCode null){ throw new BadCredentialsException(验证码过期); } //判断用户传入的验证码 是否正确 if (!realCode.equals(code)){ throw new BadCredentialsException(验证码错误); } //删除验证码 redisTemplate.delete(key); //到这里 说明验证码正确---根据手机号查询UserDetails UserDetails userDetails userDetailsService.loadUserByUsername(phone); //初始化 Authentication 设置为 已经登录 PhoneAuthenticationToken authRequest PhoneAuthenticationToken.authenticated(userDetails); //Details authRequest.setDetails(phoneAuthenticationToken.getDetails()); return authRequest; } Override public boolean supports(Class? authentication) { //判断 传入的Class类是不是当前Provider要处理的Authentication return PhoneAuthenticationToken.class.isAssignableFrom(authentication); } }6、UserDetailsServiceService(phoneLoginUserDetailsService) public class PhoneLoginUserDetailsServiceImpl implements UserDetailsService { Resource AdminUserService adminUserService; Override public UserDetails loadUserByUsername(String phone) throws UsernameNotFoundException { AdminUser adminUser adminUserService.getByPhone(phone); if (adminUser ! null){ return new LoginUserDetails(adminUser); } return null; } }7、修改配置文件import com.alibaba.fastjson2.JSON; import com.javasm.securitydemo.common.exception.R; import com.javasm.securitydemo.login.json.JsonFilter; import com.javasm.securitydemo.login.json.PhoneProvider; import com.javasm.securitydemo.login.phone.PhoneFilter; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.ProviderManager; 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.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.context.HttpSessionSecurityContextRepository; import org.springframework.security.web.context.SecurityContextRepository; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import java.io.IOException; import java.io.PrintWriter; import java.util.List; Configuration EnableWebSecurity public class SecurityConfig { //****************JSON登录--开始****************// Resource(name usernameLoginUserDetailsService) UserDetailsService userDetailsService; Bean public DaoAuthenticationProvider jsonProvider() { DaoAuthenticationProvider authenticationProvider new DaoAuthenticationProvider(); //配置 由哪个UserDetailsService负责查询用户信息UserDetails authenticationProvider.setUserDetailsService(userDetailsService); //配置密码的加密方式 authenticationProvider.setPasswordEncoder(passwordEncoder()); return authenticationProvider; } //JSON等于专属的AuthenticationManager Bean(jsonAuthManager) public AuthenticationManager jsonAuthenticationManager() { return new ProviderManager(List.of(jsonProvider())); } //配置JsonFilter public JsonFilter jsonFilter() { JsonFilter jsonFilter new JsonFilter(); //配置 AuthenticationManager jsonFilter.setAuthenticationManager(jsonAuthenticationManager()); //json登录成功之后的显示 jsonFilter.setAuthenticationSuccessHandler(this::createSuccessJson); //json登录失败之后 jsonFilter.setAuthenticationFailureHandler( (r, response, e) - createFailJson(response, e) ); //配置json登录的路径 jsonFilter.setFilterProcessesUrl(/jsonlogin); return jsonFilter; } //****************JSON登录--结束****************// //****************Phone登录--开始****************// Resource PhoneProvider phoneProvider; //手机专属的 AuthenticationManger Bean(phoneAuthManager) public AuthenticationManager phoneAuthManager() { return new ProviderManager(List.of(phoneProvider)); } Autowired public void configure(AuthenticationManagerBuilder auth) { auth.authenticationProvider(phoneProvider); } Bean public PhoneFilter phoneFilter() { PhoneFilter phoneFilter new PhoneFilter(); //配置ProviderManager phoneFilter.setAuthenticationManager(phoneAuthManager()); //json登录成功之后的显示 phoneFilter.setAuthenticationSuccessHandler(this::createSuccessJson); //json登录失败之后 phoneFilter.setAuthenticationFailureHandler( (r, response, e) - createFailJson(response, e) ); return phoneFilter; } //****************Phone登录--结束****************// Bean public SecurityContextRepository securityContextRepository() { return new HttpSessionSecurityContextRepository(); } Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.securityContext(context - context.securityContextRepository(securityContextRepository())); //因为当前json登录功能和用户名密码登录功能类似 // 所以把jsonfilter放到UsernamePasswordAuthenticaitonFilter相同的位置 http.addFilterAt(jsonFilter(), UsernamePasswordAuthenticationFilter.class); http.addFilterAt(phoneFilter(), UsernamePasswordAuthenticationFilter.class); //关闭csrf 跨域请求伪造的控制 http.csrf(csrf - csrf.disable()); http.authorizeHttpRequests( auth - auth.requestMatchers(/loginpage.html, /login/**, /jsonlogin, /phoneLogin) .permitAll() .anyRequest().authenticated() //其他页面要登录之后才能访问 );//放过登录接口以及静态页面 // ↓配置表单提交 http.formLogin(form - { // 确保认证信息被正确设置并保存到session中 form.loginPage(/loginpage.html) //自定义登录页面的路径 .loginProcessingUrl(/javasmlogin) //表单提交的路径 .usernameParameter(uname) //自定义用户名的参数名默认是username .passwordParameter(pwd) //Authentication 是 UsernamePasswordAuthenticationToken-- principal实际的值UserDetails .successHandler(this::createSuccessJson) //AuthenticationException 包含了 登录失败之后的 异常信息 .failureHandler((request, response, exception) - createFailJson(response, exception) ) .permitAll(); //以上提到的路径都放行 }).authenticationManager(jsonAuthenticationManager()); //注销登录 http.logout(logout - logout .logoutUrl(/logout) //退出登录的时候返回用户信息 .logoutSuccessHandler((r, response, a) - createSuccessJson(response, 退出登录成功)) .permitAll() ); //未登录异常提示 http.exceptionHandling().authenticationEntryPoint((request, response, e) - createFailJson(response, 当前用户未登录请先登录再访问)); return http.build(); } Bean public PasswordEncoder passwordEncoder() { //指定加密算法 return new BCryptPasswordEncoder(); } private void createSuccessJson(HttpServletRequest request,HttpServletResponse response, Authentication authentication) { SecurityContextHolderStrategy strategy SecurityContextHolder.getContextHolderStrategy(); strategy.getContext().setAuthentication(authentication); securityContextRepository().saveContext(strategy.getContext(), request, response); createSuccessJson(response,authentication); } private void createSuccessJson(HttpServletResponse response, Object object) { R ok R.ok(object); createJson(response, ok); } private void createFailJson(HttpServletResponse response, AuthenticationException e) { R error R.error(e.getMessage()); createJson(response, error); } private void createFailJson(HttpServletResponse response, String e) { R error R.error(e); createJson(response, error); } private void createJson(HttpServletResponse response, R r) { try { response.setContentType(application/json;charsetutf-8); //如果想修改返回的状态码可以这么修改 //response.setStatus(r.getCode()); //写出去 PrintWriter writer response.getWriter(); writer.write(JSON.toJSONString(r)); writer.flush(); writer.close(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } }九、跨域添加一个跨域的过滤器放到Security过滤器链中必须在登录的过滤器前面以前的跨域方式就失效了配置SpringMVC的Cors映射Configuration public class WebMvcConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**)//允许所有的 路径 .allowedOriginPatterns(*) .allowedMethods(GET,POST,PUT,DELETE) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600);//预检测请求缓冲时间 } }配置SpringSecurity的跨域支持Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration corsConfiguration new CorsConfiguration(); corsConfiguration.addAllowedOriginPattern(*);//允许所有的域名 corsConfiguration.addAllowedMethod(*);//允许所有的请求头 corsConfiguration.setAllowCredentials(true);//允许携带Cookie corsConfiguration.setMaxAge(3600L);//预检测请求缓冲时间 UrlBasedCorsConfigurationSource source new UrlBasedCorsConfigurationSource(); //对所有的路径应用配置 source.registerCorsConfiguration(/**, corsConfiguration); return source; }http.cors(cors - cors.configurationSource(corsConfigurationSource()));十、修复bug表单提交登录在写了JSON登录之后就会失效。找不到{ code: 500, msg: No AuthenticationProvider found for org.springframework.security.authentication.UsernamePasswordAuthenticationToken, timestamp: 2025-12-10T15:46:27.179768 }因为缺少了AuthenticationManager找不到处理UsernamePasswordAuthenticationToken的Provider对象修改配置添加Form表单提交需要的AuthenticationManagerhttp.formLogin(form - { form.loginPage(/loginpage.html) //自定义登录页面的路径 .loginProcessingUrl(/javasmlogin) //表单提交的路径 .usernameParameter(uname) //自定义用户名的参数名默认是username .passwordParameter(pwd) //Authentication 是 UsernamePasswordAuthenticationToken-- principal实际的值UserDetails .successHandler((request, response, authentication) - createSuccessJson(response, authentication) ) //AuthenticationException 包含了 登录失败之后的 异常信息 .failureHandler((request, response, exception) - createFailJson(response, exception) ) .permitAll(); //以上提到的路径都放行 }).authenticationManager(jsonAuthenticationManager());1、完整的SecurityConfigpackage com.javasm.securitydemo.common.config; ​ import com.alibaba.fastjson2.JSON; import com.javasm.securitydemo.common.exception.R; import com.javasm.securitydemo.login.json.JsonFilter; import com.javasm.securitydemo.login.json.PhoneProvider; import com.javasm.securitydemo.login.phone.PhoneFilter; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.ProviderManager; 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.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.context.HttpSessionSecurityContextRepository; import org.springframework.security.web.context.SecurityContextRepository; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; ​ import java.io.IOException; import java.io.PrintWriter; import java.util.List; ​ Configuration EnableWebSecurity public class SecurityConfig { ​ //****************JSON登录--开始****************// Resource(name usernameLoginUserDetailsService) UserDetailsService userDetailsService; ​ Bean public DaoAuthenticationProvider jsonProvider() { DaoAuthenticationProvider authenticationProvider new DaoAuthenticationProvider(); //配置 由哪个UserDetailsService负责查询用户信息UserDetails authenticationProvider.setUserDetailsService(userDetailsService); //配置密码的加密方式 authenticationProvider.setPasswordEncoder(passwordEncoder()); return authenticationProvider; } ​ //JSON等于专属的AuthenticationManager Bean(jsonAuthManager) public AuthenticationManager jsonAuthenticationManager() { return new ProviderManager(List.of(jsonProvider())); } ​ //配置JsonFilter public JsonFilter jsonFilter() { JsonFilter jsonFilter new JsonFilter(); //配置 AuthenticationManager jsonFilter.setAuthenticationManager(jsonAuthenticationManager()); //json登录成功之后的显示 jsonFilter.setAuthenticationSuccessHandler(this::createSuccessJson); //json登录失败之后 jsonFilter.setAuthenticationFailureHandler( (r, response, e) - createFailJson(response, e) ); //配置json登录的路径 jsonFilter.setFilterProcessesUrl(/jsonlogin); return jsonFilter; } //****************JSON登录--结束****************// ​ ​ //****************Phone登录--开始****************// Resource PhoneProvider phoneProvider; ​ //手机专属的 AuthenticationManger Bean(phoneAuthManager) public AuthenticationManager phoneAuthManager() { return new ProviderManager(List.of(phoneProvider)); } ​ Autowired public void configure(AuthenticationManagerBuilder auth) { auth.authenticationProvider(phoneProvider); } ​ Bean public PhoneFilter phoneFilter() { PhoneFilter phoneFilter new PhoneFilter(); //配置ProviderManager phoneFilter.setAuthenticationManager(phoneAuthManager()); //json登录成功之后的显示 phoneFilter.setAuthenticationSuccessHandler(this::createSuccessJson); //json登录失败之后 phoneFilter.setAuthenticationFailureHandler( (r, response, e) - createFailJson(response, e) ); return phoneFilter; } ​ //****************Phone登录--结束****************// ​ //****************跨域--开始****************// Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration corsConfiguration new CorsConfiguration(); corsConfiguration.addAllowedOriginPattern(*);//允许所有的域名 corsConfiguration.addAllowedMethod(*);//允许所有的请求头 corsConfiguration.setAllowCredentials(true);//允许携带Cookie corsConfiguration.setMaxAge(3600L);//预检测请求缓冲时间 UrlBasedCorsConfigurationSource source new UrlBasedCorsConfigurationSource(); //对所有的路径应用配置 source.registerCorsConfiguration(/**, corsConfiguration); return source; } //****************跨域--结束****************// Bean public SecurityContextRepository securityContextRepository() { return new HttpSessionSecurityContextRepository(); } ​ Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.cors(cors - cors.configurationSource(corsConfigurationSource())); http.securityContext(context - context.securityContextRepository(securityContextRepository())); ​ //因为当前json登录功能和用户名密码登录功能类似 // 所以把jsonfilter放到UsernamePasswordAuthenticaitonFilter相同的位置 http.addFilterAt(jsonFilter(), UsernamePasswordAuthenticationFilter.class); http.addFilterAt(phoneFilter(), UsernamePasswordAuthenticationFilter.class); //关闭csrf 跨域请求伪造的控制 http.csrf(csrf - csrf.disable()); http.authorizeHttpRequests( auth - auth.requestMatchers(/loginpage.html, /login/**, /jsonlogin, /phoneLogin) .permitAll() .anyRequest().authenticated() //其他页面要登录之后才能访问 );//放过登录接口以及静态页面 // ↓配置表单提交 http.formLogin(form - { // 确保认证信息被正确设置并保存到session中 form.loginPage(/loginpage.html) //自定义登录页面的路径 .loginProcessingUrl(/javasmlogin) //表单提交的路径 .usernameParameter(uname) //自定义用户名的参数名默认是username .passwordParameter(pwd) //Authentication 是 UsernamePasswordAuthenticationToken-- principal实际的值UserDetails .successHandler(this::createSuccessJson) //AuthenticationException 包含了 登录失败之后的 异常信息 .failureHandler((request, response, exception) - createFailJson(response, exception) ) .permitAll(); //以上提到的路径都放行 }).authenticationManager(jsonAuthenticationManager()); //注销登录 http.logout(logout - logout .logoutUrl(/logout) //退出登录的时候返回用户信息 .logoutSuccessHandler((r, response, a) - createSuccessJson(response, 退出登录成功)) .permitAll() ); //未登录异常提示 http.exceptionHandling().authenticationEntryPoint((request, response, e) - createFailJson(response, 当前用户未登录请先登录再访问)); return http.build(); ​ } ​ Bean public PasswordEncoder passwordEncoder() { //指定加密算法 return new BCryptPasswordEncoder(); } ​ private void createSuccessJson(HttpServletRequest request,HttpServletResponse response, Authentication authentication) { SecurityContextHolderStrategy strategy SecurityContextHolder.getContextHolderStrategy(); strategy.getContext().setAuthentication(authentication); securityContextRepository().saveContext(strategy.getContext(), request, response); createSuccessJson(response,authentication); } private void createSuccessJson(HttpServletResponse response, Object object) { R ok R.ok(object); createJson(response, ok); } ​ private void createFailJson(HttpServletResponse response, AuthenticationException e) { R error R.error(e.getMessage()); createJson(response, error); } ​ private void createFailJson(HttpServletResponse response, String e) { R error R.error(e); createJson(response, error); } ​ private void createJson(HttpServletResponse response, R r) { try { response.setContentType(application/json;charsetutf-8); //如果想修改返回的状态码可以这么修改 //response.setStatus(r.getCode()); //写出去 PrintWriter writer response.getWriter(); writer.write(JSON.toJSONString(r)); writer.flush(); writer.close(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } }第二天总结掌握Security的请求流程能用语言描述能够获取登录用户信息修改登录用户信息其他案例跟着课堂敲一遍尽可能掌握不强求
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

门户网站 建设 如何写网站界面设计中的版式设计有哪些

FaceFusion在零售门店促销视频中的店员形象批量生成 在连锁零售行业,每逢新品上市或节日促销,总部市场部最头疼的不是创意策划,而是如何让同一支广告在全国几百个门店“落地有声”。传统的做法是拍摄一条标准化视频下发——结果东北顾客看着南…

张小明 2025/12/29 9:45:55 网站建设

自己怎么制作一个公众号网站优化推广招聘

💓 博客主页:借口的CSDN主页 ⏩ 文章专栏:《热点资讯》 目录人工智能:当科技遇上人类的摸鱼日常 一、AI在医疗中的神奇操作 二、当AI遇上艺术:人类画师的内心OS 三、智能客服:是帮手还是捣乱? 四…

张小明 2025/12/29 9:45:47 网站建设

密云微网站建设建设网站写需求分析报告

料查找方式:特纳斯电子(电子校园网):搜索下面编号即可编号:T0232402M设计简介:本设计是基于STM32矿工工作安全监测,主要实现以下功能:通过传感器可以监测人体体温、心率和血氧&#…

张小明 2025/12/29 9:55:10 网站建设

三鼎网络网站建设站群优化公司

3.8 Elasticsearch-搜索模板 & Mustache 动态渲染 3.8.1 为什么需要搜索模板 在实际业务里,同一条 DSL 往往要在多个场景复用: Web、App、小程序三端检索同一批商品,只是排序字段不同;BI 报表每天凌晨跑批,查询…

张小明 2025/12/29 9:45:48 网站建设

诸暨有哪些好网站制作公司网站建设利弊

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 开发一个智能HTTP请求优化工具,能够自动检测可能导致413错误的请求。功能包括:1) 实时监控请求头中的Content-Length;2) 分析服务器配置&#xf…

张小明 2025/12/29 9:45:46 网站建设

网站能搜索到织梦怎么做门户网站

利用 Silverlight 实现 Windows 7 触摸交互 1. 认识 Silverlight Silverlight 是微软推出的一项技术,旨在通过网络为用户带来更丰富的体验。它的目标是让 Web 应用具备与桌面应用相同的保真度和质量,从而使 Web 开发者和设计师能够根据客户的特定需求构建应用程序。 Silve…

张小明 2025/12/29 9:45:52 网站建设