SpringSecurity认证授权全流程解读

 更新时间:2025年06月19日 09:54:08   作者:Nice-or-77  
这篇文章主要介绍了SpringSecurity认证授权全流程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

SpringSecurity认证流程:loadUserByUsername()方法内部实现。

实现步骤

构建一个自定义的service接口,实现SpringSecurity的UserDetailService接口。

建一个service实现类,实现此loadUserByUsername方法。

调用登录的login接口,会经过authenticationManager.authenticate(authenticationToken)方法。此方法会调用loadUserByUsername方法。

方法内部做用户信息的查询,判断用户名和密码是否正确,这是第一道认证。

@Service
@RequiredArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {


    private final SysUserMapper sysUserMapper;
    //用户登录请求/login,自动调用方法
    //根据用户名获取用户信息
    //UserDetails 存储用户信息,包括用户名,密码,权限
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getUsername, username);
        SysUser sysUser = sysUserMapper.selectOne(wrapper);
        if (Objects.isNull(sysUser)){
            throw new UsernameNotFoundException("用户名不存在");
        }
        //认证成功回UserDetails对象

        return new LoginUser(sysUser);
    }


}

@ToString
public class LoginUser implements UserDetails {

    private SysUser sysUser;

    public LoginUser(SysUser sysUser) {
        this.sysUser = sysUser;
    }

    // 权限
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return List.of();
    }

    @Override
    public String getPassword() {
        return sysUser.getPassword();
    }

    @Override
    public String getUsername() {
        return sysUser.getUsername();
    }

    // 账号是否过期
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    // 账号是否被锁定
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    // 密码是否过期
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    // 账号是否可用
    @Override
    public boolean isEnabled() {
        return true;
    }
}

如果没有查到信息就抛出异常。

如果查到信息了再接着查用户的权限信息,返回权限信息到loginUser实体。

此实体实现了SpringSecurity自带的userDetail接口。实现了getAuthorities方法。

每次查询权限都会调用此方法。

查询到的权限,会被返回到login接口。进行后续操作。

如果认证通过,通过身份信息中的userid生产一个jwt。

把完整的用户信息作为value,token作为key存入redis。

@RestController
@Tag(name = "认证模块", description = "认证模块")
@RequestMapping("/auth")
@RequiredArgsConstructor
public class AuthController {

    //注入AuthenticationManager(认证管理器)
    private final AuthenticationManager authenticationManager;

    private final JwtUtils jwtUtils;

    @PostMapping("/login")
    @Operation(summary = "登录")
    public Result login(@RequestParam("username") String username, @RequestParam("password") String password) {
        System.out.println(username + password);
        //登录逻辑
        //调用UserDetailsService.loadUserByUsername方法获取
        //不能直接调用,需要通过AuthenticationManager进行认证

        Authentication authentication = new UsernamePasswordAuthenticationToken(username, password);
        Authentication authenticate = null;
        try {
            authenticate = authenticationManager.authenticate(authentication);
        } catch (BadCredentialsException e) {
            return Result.failed(ResultCode.USERNAME_OR_PASSWORD_ERROR);
        }

        //认证成功方法token
        String token=jwtUtils.generateToken(authenticate);
        return Result.success(token);
    }
}

@Configuration
@EnableWebSecurity // 开启web安全
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfig {

    private final IgnoredUrl ignoredUrl;


    /**
     * 配置认证管理器 AuthenticationManager
     * 作用:用于身份认证
     * 参数:UserDetailsService, PasswordEncoder
     */
    @Bean
    public AuthenticationManager authenticationManager(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailsService);
        provider.setPasswordEncoder(passwordEncoder);
        return new ProviderManager(provider);
    }

    /**
     * 密码编码器
     *
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        //关闭csrf防护,否则回导致登录失败
        http.csrf(a -> a.disable()); //禁用SCRF
        //配置安全拦截规则
        http.authorizeHttpRequests(req ->
                                   req.requestMatchers(ignoredUrl.getUrls())
                                   .permitAll()
                                   .anyRequest().authenticated());
        /**
         * 配置登录页
         */
        http.formLogin(form -> form
                       .loginPage("/")
                       .successForwardUrl("/index") //登录成功跳转页面
                       .loginProcessingUrl("/login")//登录处理url
                       .failureForwardUrl("/error") //登录失败跳转页面
                       //                .usernameParameter("name")//自定义用户名参数
                       //                .passwordParameter("password")//自定义密码参数
                      );

        return http.build();
    }
}
@Component
public class JwtUtils {

    @Value("${jwt.secret}")
    private String secret;
    @Value("${jwt.expiration}")
    private Integer expiration;

    /**
     *
     */

    public String generateToken(Authentication authentication) {
        Date now = new Date();
        Date expirationDate = DateUtil.offsetSecond(now, expiration);
        Map<String, Object> claims = new HashMap<>();
        claims.put("username", authentication.getName());//用户名
        claims.put("exp", expirationDate);
        //        claims.put();
        return JWTUtil.createToken(claims, secret.getBytes());
    }
}
@Component
@Data
@ConfigurationProperties(prefix = "security.ignored")
@ToString
public class IgnoredUrl {

    private String[] urls;
}

登录成功

登陆失败

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 使用java生成激活码和密钥的方法

    使用java生成激活码和密钥的方法

    本文主要介绍了java生成激活码和密钥的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • 使用SpringBoot配置多数据源的经验分享

    使用SpringBoot配置多数据源的经验分享

    这篇文章主要介绍了使用SpringBoot配置多数据源的经验分享,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • Spring Cloud调用Ribbon的步骤

    Spring Cloud调用Ribbon的步骤

    Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。本文将讲述Spring Cloud调用Ribbon的方法
    2021-05-05
  • Springboot整合SpringSecurity实现登录认证和鉴权全过程

    Springboot整合SpringSecurity实现登录认证和鉴权全过程

    这篇文章主要介绍了Springboot整合SpringSecurity实现登录认证和鉴权全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • Mybatis多条数据只返回一条的问题及解决

    Mybatis多条数据只返回一条的问题及解决

    文章介绍了在MyBatis中进行联查时,如果只返回主表数据而子表数据相同,可能会导致重复数据的问题,解决方法是在主表对象中添加一个临时字段,并将子表的不同数据封装到主表中,从而避免重复数据的返回
    2026-03-03
  • 解决struts2 拦截器修改request的parameters参数失败的问题

    解决struts2 拦截器修改request的parameters参数失败的问题

    这篇文章主要介绍了解决struts2 拦截器修改request的parameters参数失败的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • C语言指针数组案例详解

    C语言指针数组案例详解

    这篇文章主要介绍了C语言指针数组案例详解,本文通过案例详细的解释了指针与数组的初始化还有关系与应用,需要的朋友可以参考下这篇文章
    2021-07-07
  • Java线程在什么情况下可以终止

    Java线程在什么情况下可以终止

    Thread线程类自带的stop方法,但是jdk不建议使用,因为stop方法终止线程只是强行终止,内存中部分值可能已发生变化,并未保证数据的一致性,将会导致线程安全问题,那么在什么情况下可以终止线程呢,本篇带你探究一下
    2022-04-04
  • Springboot-admin整合Quartz实现动态管理定时任务的过程详解

    Springboot-admin整合Quartz实现动态管理定时任务的过程详解

    Quartz是一款Java编写的开源任务调度框架,同时它也是Spring默认的任务调度框架,它的作用其实类似于Timer定时器以及ScheduledExecutorService调度线程池,这篇文章主要介绍了Springboot-admin整合Quartz实现动态管理定时任务,需要的朋友可以参考下
    2023-04-04
  • 性能爆棚的实体转换复制工具MapStruct使用详解

    性能爆棚的实体转换复制工具MapStruct使用详解

    这篇文章主要为大家介绍了性能爆棚的实体转换复制工具MapStruct使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03

最新评论