栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring Security

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Security

目录

04、Spring Security从数据库中读取信息

pom依赖

application.properties 

User

1.每个实体类的属性名都不一样,怎么知道你哪个字段表示用户名,那个字段表示密码,Spring Security提供了统一的方法实现UserDetails 接口

2.先重写方法,再实现get和set方法

3.重写了自动的,记得删掉get方法

UserService 

当用户登录的时候,会自动调用到这个方法

UserMapper

UserMapper.xml

 05、Spring Security自定义登录接口

LoginController

1.AuthenticationManager 就是 Spring Security 中的认证器,这是一个接口,这个接口只有一个实现类,ProviderManager,用户登录时侯具体的校验工作,就是由它来完成的。

2.new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());:拿到用户名和密码构建登录令牌

3.authenticationManager.authenticate(token);//这一步就是去执行登录

4.自定义登录接口要手动存信息进SecurityContextHolder

SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(token.getPrincipal(), null, token.getAuthorities()));

5.登录失败抛出的异常

SecurityConfig

1.注册LoginController的AuthenticationManager的认证器到spring中去

2.configure(HttpSecurity http)过滤登录接口

 06、Spring Security密码加密

内部源码:PasswordEncoder :Ctrl+h可以查看他的实现类

1.encode密码加密

2.matches(明文密码,加密密码)密码匹对:登录会自动帮你执行

3.upgradeEncoding密码升级

Security02ApplicationTests

测试BCryptPasswordEncoder加密:密码自带盐值

new BCryptPasswordEncoder(10);可以设置密码强度,加密起来慢,对于破解也慢了

 SecurityConfig

  06、Spring Security新的加密方法逐步替代原有的加密方法

内部源码:PasswordEncoderFactories

SecurityConfig

1.如果我们没有手动配置密码加密工具,那么默认PasswordEncoder,实际上是DelegatingPasswordEncoder

2.DelegatingPasswordEncoder 代理了所有密码加密器,他会根据密码的字符串格式,而选择一个合适的加密工具

3.例如数据库前缀{noop}

 

数据库可以多种加密方案共存

如何实现数据库统一类型密码加密-升级不同类型的密码

UserService

1.密码升级,实现UserDetailsPasswordService 接口

2.重新方法: *当用户登录的时候,会去自动检查当前用户密码是不是bcrypt,如果不是,则会自动进行密码升级,那么就会触发该方法

3.在这个方法种更新密码

UserService

 UserMapper.xml

升级同等类型的密码 

SecurityConfig

1.首先要有passwordEncoder 统一的密码加密类型

2.重写PasswordEncoderFactories加入@Bean改变密码强度


04、Spring Security从数据库中读取信息

pom依赖

        
            org.springframework.boot
            spring-boot-starter-security
        

        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter                                             2.2.2
        

        
            com.alibaba
            druid
            1.2.9
        

        
            mysql
            mysql-connector-java
            runtime
        

    
        
            
                src/main/java
                
                    **
    @Override
    public Collection getAuthorities() {
        return null;
    }

    
    @Override
    public String getPassword() {
        return password;
    }

    
    @Override
    public String getUsername() {
        return username;
    }

    
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    
    @Override
    public boolean isEnabled() {
        return enabled;
    }
}

UserService 

当用户登录的时候,会自动调用到这个方法
@Service
public class UserService implements UserDetailsService {

    @Autowired
    UserMapper userMapper;

    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userMapper.loadUserByUsername(username);
        if (user == null) {
            //说明用户名不存在,这个异常最终会被隐藏起来,转而抛出 BadCredentialsException
            throw new UsernameNotFoundException("用户不存在");
        }
        return user;
    }
}

UserMapper
@Mapper
public interface UserMapper {
    User loadUserByUsername(String username);
}

UserMapper.xml



    select * from user where username=#{username};
    

 05、Spring Security自定义登录接口

LoginController

1.AuthenticationManager 就是 Spring Security 中的认证器,这是一个接口,这个接口只有一个实现类,ProviderManager,用户登录时侯具体的校验工作,就是由它来完成的。

2.new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());:拿到用户名和密码构建登录令牌

3.authenticationManager.authenticate(token);//这一步就是去执行登录

4.自定义登录接口要手动存信息进SecurityContextHolder

SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(token.getPrincipal(), null, token.getAuthorities()));

5.登录失败抛出的异常
@RestController
public class LoginController {

    
    @Autowired
    AuthenticationManager authenticationManager;

    
    @PostMapping("/login")
    public Map login(@RequestBody User user) {
        Map map = new HashMap<>();
        //构建登录令牌
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
        try {
            //这一步就是去执行登录,类似于 shiro 中的 subject.login 方法
            authenticationManager.authenticate(token);
            //将当前登录成功的用户信息存入到 SecurityContextHolder 中
            SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(token.getPrincipal(), null, token.getAuthorities()));
            map.put("status", "200");
            map.put("message", "登录成功");
        } catch (AuthenticationException exception) {
            //登录失败
            map.put("status", "500");
            if (exception instanceof BadCredentialsException) {
                map.put("message", "用户名或者密码写错,登录失败");
            } else if (exception instanceof UsernameNotFoundException) {
                //出于安全考虑,Spring Security 内部将 UsernameNotFoundException 隐藏起来了,转而抛出了 BadCredentialsException
            } else if (exception instanceof AccountExpiredException) {
                map.put("message", "账户过期,登录失败");
            } else if (exception instanceof CredentialsExpiredException) {
                map.put("message", "密码过期,登录失败");
            } else if (exception instanceof DisabledException) {
                map.put("message", "账户被禁用,登录失败");
            } else if (exception instanceof LockedException) {
                map.put("message", "账户被锁定,登录失败");
            }
        }
        return map;
    }

SecurityConfig

1.注册LoginController的AuthenticationManager的认证器到spring中去

2.configure(HttpSecurity http)过滤登录接口
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
                //从 Spring Security 过滤器链中移除 CsrfFilter
                .csrf().disable();
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

 06、Spring Security密码加密

内部源码:PasswordEncoder :Ctrl+h可以查看他的实现类

1.encode密码加密

2.matches(明文密码,加密密码)密码匹对:登录会自动帮你执行

3.upgradeEncoding密码升级

4.自带盐值,相同的明文加密成密码不同

public interface PasswordEncoder {

   String encode(CharSequence rawPassword);

   boolean matches(CharSequence rawPassword, String encodedPassword);

   default boolean upgradeEncoding(String encodedPassword) {
      return false;
   }

}

Security02ApplicationTests

测试BCryptPasswordEncoder加密:密码自带盐值

new BCryptPasswordEncoder(10);可以设置密码强度,加密起来慢,对于破解也慢了

@SpringBootTest
class Security02ApplicationTests {

    @Test
    void contextLoads() {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(10);
        for (int i = 0; i < 10; i++) {
            System.out.println(encoder.encode("123"));
        }
    }

}

$2a$10$NqbXkorf.Df13lefBvZspuD9wHj9CH3KUAYQCOBvqDRyze8XPVck6
$2a$10$kFIsIVV1y0Zuvs1cggzqnuZ7Qzgq0whzf3ozf0iGmbAxvBi731mji
$2a$10$giZViF92vIsZF6jrlERRB.lJm2XcMU8H/u3wox3QWCBDy9aLukcGK
$2a$10$UtWGZsdlBiLatF1CGGFC.uXibKwqydjS1Nb0ob5fGuVZyHi//NjwK
$2a$10$.TsjcfVJ0RYfAkREUM.RE.yfKrPrskRWflDjyxbo83QjkOKzsmU2C
$2a$10$lDppXh3Z32Q3qlpKdpXB8OP6UKKwRPlNqRV1CBtJ/BWl8XEuHh1a6
$2a$10$jpEDlzw36HGaSibKJpeu.uAn0YU9BhhjFrgoLAd8MGE1bkdr7zMW2
$2a$10$is5sKcAajPNQTTfojjjJvuSlY7s1VAe5kcyDoa7pWCGcmwETKglVi
$2a$10$eMoBXb3slmXSl/OM9Rjg2O1AYKZQdOtECZzh01YwmhDLxQbBrcwgi
$2a$10$wZP9XblkBXVwMdV4UiXyKubOcEW0zWgxOJVVGsz5p69l9.C2TU5t.

 SecurityConfig
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
                //从 Spring Security 过滤器链中移除 CsrfFilter
                .csrf().disable();
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

  06、Spring Security新的加密方法逐步替代原有的加密方法

内部源码:PasswordEncoderFactories
public static PasswordEncoder createDelegatingPasswordEncoder() {
   String encodingId = "bcrypt";
   Map encoders = new HashMap<>();
   encoders.put(encodingId, new BCryptPasswordEncoder());
   encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder());
   encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder());
   encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));
   encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());
   encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
   encoders.put("scrypt", new SCryptPasswordEncoder());
   encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1"));
   encoders.put("SHA-256",
         new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));
   encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
   encoders.put("argon2", new Argon2PasswordEncoder());
//代理密码加密器
   return new DelegatingPasswordEncoder(encodingId, encoders);
}
SecurityConfig

1.如果我们没有手动配置密码加密工具,那么默认PasswordEncoder,实际上是DelegatingPasswordEncoder

2.DelegatingPasswordEncoder 代理了所有密码加密器,他会根据密码的字符串格式,而选择一个合适的加密工具

3.例如数据库前缀{noop}

    
//    @Bean
//    PasswordEncoder passwordEncoder() {
//        return new BCryptPasswordEncoder();
//    }

数据库可以多种加密方案共存

如何实现数据库统一类型密码加密-升级不同类型的密码

UserService

1.密码升级,实现UserDetailsPasswordService 接口

2.重新方法: *当用户登录的时候,会去自动检查当前用户密码是不是bcrypt,如果不是,则会自动进行密码升级,那么就会触发该方法

3.在这个方法种更新密码
@Service
public class UserService implements UserDetailsService, UserDetailsPasswordService {

    @Autowired
    UserMapper userMapper;

    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userMapper.loadUserByUsername(username);
        if (user == null) {
            //说明用户名不存在,这个异常最终会被隐藏起来,转而抛出 BadCredentialsException
            throw new UsernameNotFoundException("用户不存在");
        }
        return user;
    }

 
 
@Override
public UserDetails updatePassword(UserDetails user, String newPassword) {
    Integer i = userMapper.updatePassWordByUsernam(newPassword,user.getUsername());
    if (i == 1){
       User user1 = (User) user;
       user1.setPassword(newPassword);
       return user1;
    }
    return user;
}
UserService
@Mapper
public interface UserMapper {
    User loadUserByUsername(String username);

    Integer updatePassWordByUsernam(@Param("password") String newPassword, @Param("username")String username);
}

 UserMapper.xml

    
        update user set password = #{password} where username;
    


    

升级同等类型的密码  SecurityConfig

1.首先要有passwordEncoder 统一的密码加密类型

2.重写PasswordEncoderFactories加入@Bean改变密码强度
@Bean
PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

@Bean
public static PasswordEncoder createDelegatingPasswordEncoder() {
    String encodingId = "bcrypt";
    Map encoders = new HashMap<>();
    encoders.put(encodingId, new BCryptPasswordEncoder(20));
    encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder());
    encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder());
    encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));
    encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());
    encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
    encoders.put("scrypt", new SCryptPasswordEncoder());
    encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1"));
    encoders.put("SHA-256",
            new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));
    encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
    encoders.put("argon2", new Argon2PasswordEncoder());
    return new DelegatingPasswordEncoder(encodingId, encoders);
}
 07、权限控制(核心功能) 1.HelloController:注明权限接口
  • 设置可以访问的角色@PreAuthorize("hasRole('ROLE_user')")
@RestController
public class HelloController {

    
    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }

    
    @GetMapping("/user/hello")
    @PreAuthorize("hasRole('ROLE_user')")
    public String user() {
        return "hello user";
    }

    
    @GetMapping("/admin/hello")
    @PreAuthorize("hasRole('ROLE_admin')")
    public String admin() {
        return "hello admin";
    }
2.SecurityConfig:设置权限
  • .antMatchers("/admin @Override public Collection getAuthorities() { // SimpleGrantedAuthority是他唯一的实现类 List list = new ArrayList<>(); return list; // return roles.stream().map(r -> new SimpleGrantedAuthority(r.getName())).collect(Collectors.toList()); } @Override public String getPassword() { return password; } @Override public String getUsername() { return username; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return enabled; } }  5.UserService:在登录的成功的时候拿到用户角色
    @Autowired
    UserMapper userMapper;
    
    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userMapper.loadUserByUsername(username);
        if (user == null) {
            //说明用户名不存在,这个异常最终会被隐藏起来,转而抛出 BadCredentialsException
            throw new UsernameNotFoundException("用户不存在");
        }
        //如过查询到了用户,接下来就去查询用户的角色
        user.setRoles(userMapper.getUserRolesByUid(user.getId()));
        return user;
    }
    UserMapper
    @Mapper
    public interface UserMapper {
        User loadUserByUsername(String username);
    
        Integer updatePassWordByUsername(@Param("password") String newPassword, @Param("username")String username);
    
        List getUserRolesByUid(Integer uid);
    }

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/922381.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号