ToB企服应用市场:ToB评测及商务社交产业平台

标题: Spring Security使用指南 [打印本页]

作者: 刘俊凯    时间: 2025-1-9 10:44
标题: Spring Security使用指南
        文章讲解了Spring Security的各个模块和功能。此中包罗用户认证、脚色授权、暗码加密和解密等。文章还提供了详细的代码示例,资助读者快速上手并明白Spring Security的使用。总之,本文是一篇全面而实用的Spring Security使用指南,对于想要学习和使用Spring Security的开辟者来说是一份非常有价值的资料。

一、入门使用

1,引入依靠

  1.         <dependency>
  2.             <groupId>org.springframework.boot</groupId>
  3.             <artifactId>spring-boot-starter-security</artifactId>
  4.         </dependency>
复制代码
2,访问请求

假设有如下的接口,当访问时会主动下载权限框架的登录页请求



3,自定义登录页

准备自定义的静态资源

添加设置
  1. @Configuration
  2. public class SecurityConfig {
  3.   @Bean
  4.   public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  5.     // 配置表单登录
  6.     http.formLogin()
  7.         // 指定自定义的登录页面 URL
  8.         .loginPage("/login.html")
  9.         // 指定登录请求的处理 URL
  10.         .loginProcessingUrl("/login")
  11.         // 允许所有用户访问登录页面和登录处理 URL
  12.         .permitAll()
  13.         .and()
  14.         // 配置授权请求
  15.         .authorizeRequests()
  16.         // 允许所有用户访问以下路径
  17.         .antMatchers( "/css/**", "/js/**", "/images/**")
  18.         .permitAll()
  19.         // 对于其他所有请求,要求用户必须经过身份验证
  20.         .anyRequest()
  21.         .authenticated()
  22.         .and()
  23.         // 禁用 CSRF 保护
  24.         .csrf()
  25.         .disable();
  26.     // 构建并返回安全过滤链
  27.     return http.build();
  28.   }
  29. }
复制代码
呈现结果



二、自定义认证

1,基于内存的认证

  1.     @Bean
  2.     PasswordEncoder passwordEncoder() {
  3.         return NoOpPasswordEncoder.getInstance();
  4.     }
  5.     @Bean
  6.     public UserDetailsService users() {
  7.         UserDetails user = User.builder()
  8.                 .username("user")
  9.                 .password("123456")
  10.                 .roles("USER")
  11.                 .build();
  12.         UserDetails admin = User.builder()
  13.                 .username("admin")
  14.                 .password("112233")
  15.                 .roles("USER", "ADMIN")
  16.                 .build();
  17.         return new InMemoryUserDetailsManager(user, admin);
  18.     }
复制代码
2,BCrypt暗码加密

BCrypt就是一款加密工具,可以比较方便地实现数据的加密工作。也可以简单明白为它内部自己实现了随机加盐处理。比方,使用MD5加密,每次加密后的密文其实都是一样的,这样就方便了MD5通过大数据的方式进行破解。BCrypt生成的密文长度是60,而MD5的长度是32。
  1. import org.springframework.security.crypto.bcrypt.BCrypt;
  2. public class Main {
  3.     public static void main(String[] args) {
  4.         byte[] bytes = "123456".getBytes();
  5.         System.out.println(bytes);
  6.         String hashpw = BCrypt.hashpw(bytes, BCrypt.gensalt());
  7.         System.out.println("password-one:" + hashpw);
  8.         String hash = BCrypt.hashpw(bytes, BCrypt.gensalt());
  9.         System.out.println("password-two:" + hash);
  10.         System.out.println("------------------------");
  11.         System.out.println(BCrypt.checkpw(bytes, hash));
  12.         System.out.println(BCrypt.checkpw(bytes, hashpw));
  13.         System.out.println(BCrypt.checkpw("123456", hashpw));
  14.     }
  15. }
复制代码



三、基于JDBC数据库实现认证

1,执行流程


2,基于内存代码执行

在Spring Security框架中提供了一个UserDetailsService 接口,它的主要作用是提供用户详细信息。详细来说,当用户尝试进行身份验证时,UserDetailsService 会被调用,以获取与用户相关的详细信息。这些详细信息包罗用户的用户名、暗码、脚色等
  1. import org.springframework.security.core.userdetails.User;
  2. import org.springframework.security.core.userdetails.UserDetails;
  3. import org.springframework.security.core.userdetails.UserDetailsService;
  4. import org.springframework.security.core.userdetails.UsernameNotFoundException;
  5. import org.springframework.stereotype.Component;
  6. @Component
  7. public class UserDetailsServiceImpl implements UserDetailsService {
  8.     @Override
  9.     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  10.         if (username.equals("user")) {
  11.             return User.builder()
  12.                     .username(username)
  13.                     .password("$2a$10$mPMldGTPYijVDItlA3/SsuAlv8OK2Rfz7VNbgdU4peyDCsxRqS95y")
  14.                     .roles("USER")
  15.                     .build();
  16.         }
  17.         if (username.equals("admin")) {
  18.             return User.builder()
  19.                     .username(username)
  20.                     .password("$2a$10$mPMldGTPYijVDItlA3/SsuAlv8OK2Rfz7VNbgdU4peyDCsxRqS95y")
  21.                     .roles("USER", "ADMIN")
  22.                     .build();
  23.         }
  24.         return null;
  25.     }
  26. }
复制代码
3,基于数据库代码执行

  1. @Component
  2. public class UserDetailsServiceImpl implements UserDetailsService {
  3.     @Autowired
  4.     private UserMapper userMapper;
  5.     @Override
  6.     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  7.         // 根据用户名查询用户
  8.         User user = userMapper.findByUsername(username);
  9.         Assert.isTrue(user != null, "用户不存在");
  10.         // 建立角色
  11.         SimpleGrantedAuthority userRole = new SimpleGrantedAuthority("user");
  12.         SimpleGrantedAuthority adminRole = new SimpleGrantedAuthority("admin");
  13.         List<SimpleGrantedAuthority> roleList = new ArrayList<>();
  14.         roleList.add(userRole);
  15.         roleList.add(adminRole);
  16.         return new org.springframework.security.core.userdetails.User(user.getUsername(),
  17.                 user.getPassword(), roleList);
  18.     }
  19.    
  20. }
复制代码
4,自定义框架的USER类

  1. import lombok.Data;
  2. import org.springframework.security.core.GrantedAuthority;
  3. import org.springframework.security.core.authority.SimpleGrantedAuthority;
  4. import org.springframework.security.core.userdetails.UserDetails;
  5. import java.util.Collection;
  6. import java.util.List;
  7. import java.util.stream.Collectors;
  8. @Data
  9. public class UserAuth implements UserDetails {
  10.     private String username; //固定不可更改
  11.     private String password;//固定不可更改
  12.     private String nickName;  //扩展属性  昵称
  13.     private List<String> roles; //角色列表
  14.     @Override
  15.     public Collection<? extends GrantedAuthority> getAuthorities() {
  16.         if (roles == null) return null;
  17.         return roles.stream()
  18.                 .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
  19.                 .collect(Collectors.toList());
  20.     }
  21.     @Override
  22.     public boolean isAccountNonExpired() {
  23.         return true;
  24.     }
  25.     @Override
  26.     public boolean isAccountNonLocked() {
  27.         return true;
  28.     }
  29.     @Override
  30.     public boolean isCredentialsNonExpired() {
  31.         return true;
  32.     }
  33.     @Override
  34.     public boolean isEnabled() {
  35.         return true;
  36.     }
  37. }
复制代码
  1. @Component
  2. public class UserDetailsServiceImpl implements UserDetailsService {
  3.     @Autowired
  4.     private UserMapper userMapper;
  5.     @Override
  6.     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  7.         // 根据用户名查询用户
  8.         User user = userMapper.findByUsername(username);
  9.         Assert.isTrue(user != null, "用户不存在");
  10.         UserAuth userAuth = new UserAuth();
  11.         BeanUtils.copyProperties(user, userAuth);
  12.         // 建立角色
  13.         List<String> roles=new ArrayList<>();
  14.         if ("user@qq.com".equals(user.getUsername())) {
  15.             roles.add("USER");
  16.         }
  17.         if ("admin@qq.com".equals(user.getUsername())) {
  18.             roles.add("USER");
  19.             roles.add("ADMIN");
  20.         }
  21.         userAuth.setRoles(roles);
  22.         return userAuth;
  23.     }
  24. }
复制代码
  // 获取认证对象主体
UserAuth userAuth = (UserAuth) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
  四、授权

1,简单WEB授权

新增两个接口

分配脚色

当使用user脚色访问/admin时,便会返回403权限不足

2,控制利用方法

● permitAll() 方法,所有用户可访问。
● denyAll() 方法,所有用户不可访问。
● authenticated() 方法,登录用户可访问。
● anonymous() 方法,匿名用户可访问。
● rememberMe() 方法,通过 remember me 登录的用户可访问。
● fullyAuthenticated() 方法,非 remember me 登录的用户可访问。
● hasIpAddress(String ipaddressExpression) 方法,来自指定 IP 表达式的用户可访问。
● hasRole(String role) 方法, 拥有指定脚色的用户可访问,传入的脚色将被主动增长 “ROLE_”   前缀。 
● hasAnyRole(String... roles) 方法,拥有指定任意脚色的用户可访问。传入的脚色将被主动增长 “ROLE_” 前缀。
● hasAuthority(String authority) 方法,拥有指定权限( authority )的用户可访问。
● hasAnyAuthority(String... authorities) 方法,拥有指定任意权限( authority )的用户可访问。

5、整合JWT

1,实现流程


2,注册认证管理

  1. @Configuration
  2. public class SecurityConfig {
  3.   @Bean
  4.   public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  5.     http.authorizeRequests().antMatchers("/security/login").permitAll();
  6.     http.csrf().disable();
  7.     return http.build();
  8.   }
  9.   @Bean
  10.   public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
  11.     return configuration.getAuthenticationManager();
  12.   }
  13.   @Bean
  14.   public PasswordEncoder passwordEncoder() {
  15.     return new BCryptPasswordEncoder();
  16.   }
  17.   @Bean
  18.   public UserDetailsService users() {
  19.     UserDetails user = User.builder()
  20.         .username("user")
  21.         .password("$2a$10$2VCyByZ5oeiXCEN73wvBB.xpmJgPBbZVS/Aallmdyij2G7hmAKQTG")
  22.         .roles("USER")
  23.         .build();
  24.     UserDetails admin = User.builder()
  25.         .username("admin")
  26.         .password("$2a$10$cRH8iMMh6XO0T.ssZ/8qVOo8ThWs/qfntIH3a7yfpbPd05h9ZGx8y")
  27.         .roles("USER", "ADMIN")
  28.         .build();
  29.     return new InMemoryUserDetailsManager(user, admin);
  30.   }
  31. }
复制代码
3,登录接口

  1. @PostMapping("/login")
  2.     public String login(@RequestBody LoginDto loginDto){
  3.         // 使用接收到的用户名和密码创建一个认证令牌对象。
  4.         UsernamePasswordAuthenticationToken authenticationToken =
  5.             new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword());
  6.         // 调用Spring Security的认证管理器来验证提供的认证令牌。
  7.         // 如果用户名或密码不正确,这一步会抛出异常。
  8.         Authentication authenticate = authenticationManager.authenticate(authenticationToken);
  9.         if (authenticate.isAuthenticated()) {
  10.             // 获取认证成功的主体
  11.             Object principal = authenticate.getPrincipal();
  12.             Map<String, Object> claims = new HashMap<>();
  13.             claims.put("user", principal);
  14.             String token = JWTUtil.createToken(claims, JWT_KEY.getBytes());
  15.             log.info("token: {}", token);
  16.             return token;
  17.         }
  18.         return "";
  19.     }
复制代码
4,自定义认证管理

  1. @Component
  2. public class TokenAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
  3.   @Override
  4.   public AuthorizationDecision check(Supplier<Authentication> authentication,
  5.                                      RequestAuthorizationContext requestAuthorizationContext) {
  6.     HttpServletRequest request = requestAuthorizationContext.getRequest();
  7.     String token = request.getHeader("token");
  8.     if (!StringUtils.hasText(token)) {
  9.       return new AuthorizationDecision(false);
  10.     }
  11.     Claims claims = JwtUtil.parseJWT(JWT_KEY, token);
  12.     //获取userAuth
  13.     UserAuth user = JSONObject.parseObject(JSON.toJSONString(claims.get("user")),UserAuth.class);
  14. //存入上下文
  15.         UsernamePasswordAuthenticationToken auth
  16.                 =new UsernamePasswordAuthenticationToken( userAuth, userAuth.getPassword(), userAuth.getAuthorities());
  17.         SecurityContextHolder.getContext().setAuthentication(auth);
  18.     if (user != null) {
  19.       return new AuthorizationDecision(false);
  20.     }
  21.     String requestURI = request.getRequestURI();
  22.     if (user.getRoles().contains("admin")) {
  23.       if("/hello/admin".equals(requestURI)){
  24.         return new AuthorizationDecision(true);
  25.       }
  26.     }
  27.     if(user.getRoles().contains("USER")){
  28.       if("/hello/user".equals(requestURI)){
  29.         return new AuthorizationDecision(true);
  30.       }
  31.     }
  32.     return new AuthorizationDecision(false);
  33.   }
  34. }
复制代码
  1.   @Autowired
  2.   private TokenAuthorizationManager tokenAuthorizationManager;
  3.   @Bean
  4.   public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  5.     http.authorizeHttpRequests().antMatchers("/security/login").permitAll()
  6.         .anyRequest().access(tokenAuthorizationManager);
  7.     http.csrf().disable();
  8.         //关闭session
  9.         http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
  10.         //关闭缓存
  11.         http.headers().cacheControl().disable();
  12.     return http.build();
  13.   }
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4