当前位置: 首页> 教育> 大学 > 个人如何建立免费手机网站_百家号权重查询站长工具_seo招聘要求_关键词录入榜

个人如何建立免费手机网站_百家号权重查询站长工具_seo招聘要求_关键词录入榜

时间:2025/7/11 10:38:20来源:https://blog.csdn.net/RookieSa/article/details/144487419 浏览次数:0次
个人如何建立免费手机网站_百家号权重查询站长工具_seo招聘要求_关键词录入榜

环境说明:

  1. JDK:17
  2. Spring Boot: 3.4.0
  3. Spring Security: 6.4

0X00 概要

目标:

  1. 实现一个登录接口且配置该接口不需要认证;
  2. 实现 JWT 的认证;
  3. 自定义认证失败;

0x01 基础配置

密码编码格式的设置

// cn.keeploving.demo.config.SecurityConfig@Bean
public PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();
}

实现 UserDetailsService,该接口仅有一个方法:loadUserByUsername,是根据登录的凭证(如:用户名、手机号、邮箱等)获取用信息的。

// cn.keeploving.demo.config.SecurityConfig@Bean
public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {// 这里使用 memory的,也可以自己继承进行实现// 这里就意味着有一个账号test,密码是 abc@123return new InMemoryUserDetailsManager(new User("test",passwordEncoder.encode("abc@123"),new ArrayList<>()));
}

0x02 登录接口的实现

基本的登录接口的需要实现一下功能:

  1. 验证登录输入的验证码(如果有);
  2. 检查账号是否存在、密码是否正确,不存在(正确)则返回提示信息,如:用户名或密码错误;
  3. 检查账号的其他状态,返回对应的提示信息,如:账号已经锁定;
  4. 验证成功返回 JWT。

使用 Spring security 认证时需要先注入 AuthenticationManager,代码如下:

// cn.keeploving.demo.config.SecurityConfig@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {return configuration.getAuthenticationManager();
}

然后使用 AuthenticationManager 的 authenticate 方法进行认证是会抛出异常,如下:

  • BadCredentialsException:当登录凭证(如密码)错误时抛出的异常
  • UsernameNotFoundException:未找到账号时抛出异常
  • DisabledException:账号被禁用时抛出的异常
  • LockedException:账号被锁定时抛出的异常

还有更多可能排除的异常,但是这几个异常是和账号信息有关的,它们都是 AccountStatusException 的子类,所以登录时可以捕获它们来返回登录失败信息,具体的代码如下:

// cn.keeploving.demo.controller.AuthController@RestController
@RequestMapping("auth")
public class AuthController {@Autowiredprivate AuthenticationManager authenticationManager;@PostMapping("/login")public String login(@RequestBody LoginDto loginDto) {// TODO:验证验证码// 登录认证UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword());try {Authentication authenticate = authenticationManager.authenticate(token);SecurityContextHolder.getContext().setAuthentication(authenticate);// 生成JWT并返回Date now = new Date();return Jwts.builder().signWith(ValuePool.KEY)// token 携带的信息.claim("username", loginDto.getUsername())// 设置过期时间.setExpiration(new Date(now.getTime() + 8 * 60 * 60 * 1000)).compact();} catch (BadCredentialsException | UsernameNotFoundException exp) {return "用户名或密码错误";} catch (LockedException | AccountExpiredException exp) {return "账号信息异常,请联系管理员处理";}}
}

此时请求 /auth/login 接口会返回 401。Spring security 默认会拒绝非 /login 的请求并跳转到 /login 页面,可以在该页面使用配置的 test 账号进行登录;

前后端分离需要关闭 form 登录并且开放 /auth/login 接口,配置如下:

// cn.keeploving.demo.config.SecurityConfig@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {return http.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests(registry -> {// 允许 /auth/login 接口访问registry.requestMatchers("/auth/login").permitAll();// 其他的需要认证registry.anyRequest().authenticated();})// 关闭 form.formLogin(AbstractHttpConfigurer::disable).build();
}

配置 /auth/login 不需要认证就可以访问,其他的请求需要认证才可以访问

0x03 认证 JWT

通过 Filter 对请求进行拦截获取 JWT,获取到 JWT 后要对 JWT 进行解析、判断,符合要求后就要生成 Spring Security 需要的 Token 信息。具体实现的代码如下:

// cn.keeploving.demo.filter.JwtFilterpublic class JwtFilter extends HttpFilter {private final JwtParser build = Jwts.parserBuilder().setSigningKey(ValuePool.KEY).build();private static final Logger LOG = LoggerFactory.getLogger(JwtFilter.class);private final UserDetailsService userDetailsService;public JwtFilter(UserDetailsService userDetailsService) {this.userDetailsService = userDetailsService;}@Overrideprotected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {String token = doGetJwtToken(request);if (token == null) {// 交给后续处理chain.doFilter(request, response);return;}try {// 解析 TOKENJws<Claims> claimsJws = build.parseClaimsJws(token);String username = claimsJws.getBody().get("username", String.class);// 检验 TOKENUserDetails userDetails = userDetailsService.loadUserByUsername(username);if (userDetails == null) {throw new BadCredentialsException("异常的认证信息");}// 生成上下文使用的 TOKENUsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(username, "", userDetails.getAuthorities());authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));SecurityContextHolder.getContext().setAuthentication(authToken);} catch (Exception exp) {LOG.error("JWT解析失败: ", exp);}chain.doFilter(request, response);}private String doGetJwtToken(HttpServletRequest request) {String authorization = request.getHeader("Authorization");if (authorization == null) {return null;}return authorization.replace("Bearer ", "");}}

开发完 Filter 后还需要配置 Filter 的顺序,具体配置如下:

// cn.keeploving.demo.config.SecurityConfig@Bean
public SecurityFilterChain filterChain(HttpSecurity http, UserDetailsService service) throws Exception {return http.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests(registry -> {registry.requestMatchers("/auth/login").permitAll();registry.anyRequest().authenticated();}).formLogin(AbstractHttpConfigurer::disable)// 添加 Filter.addFilterBefore(new JwtFilter(service), UsernamePasswordAuthenticationFilter.class).build();
}

开发一个 self 接口获取用户登录成功之后的信息:

// cn.keeploving.demo.controller.AuthController@GetMapping("/self")
public Object self() {Authentication authentication = SecurityContextHolder.getContext().getAuthentication();Object principal = authentication.getPrincipal();return principal;
}

携带登录成功后乡响应的 jwt 即可拿到登录用户的 username。

0x04 认证失败的处理

默认认证失败后响应空白内容并且将响应状态设置为 403,部分项目会有自己的定制化需求,可以配置 exceptionHandling 进行设置。
实现 AccessDeniedHandler 和 AuthenticationEntryPoint 就可以实现请求被拒绝、认证异常的响应,具体代码如下:

public class CustomAccessDeniedHandler implements AccessDeniedHandler, AuthenticationEntryPoint {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {doErrorResp(response);}@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {doErrorResp(response);}private static void doErrorResp(HttpServletResponse response) throws IOException {response.setStatus(HttpStatus.FORBIDDEN.value());response.setContentType("application/json");response.setHeader("content-type", "application/json");response.setCharacterEncoding("UTF-8");response.getWriter().write("拒绝访问");response.getWriter().flush();}

配置如下:

// cn.keeploving.demo.config.SecurityConfig@Bean
public SecurityFilterChain filterChain(HttpSecurity http, UserDetailsService service) throws Exception {return http.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests(registry -> {registry.requestMatchers("/auth/login").permitAll();registry.anyRequest().authenticated();}).exceptionHandling(config -> {CustomAccessDeniedHandler handler = new CustomAccessDeniedHandler();config.accessDeniedHandler(handler);config.authenticationEntryPoint(handler);}).formLogin(AbstractHttpConfigurer::disable).addFilterBefore(new JwtFilter(service), UsernamePasswordAuthenticationFilter.class).build();
}

请求 /auth/self 不携带 JWT 或者携带错误的 JWT 都会响应:拒绝访问

关键字:个人如何建立免费手机网站_百家号权重查询站长工具_seo招聘要求_关键词录入榜

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: