欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于Spring Security實現(xiàn)對密碼進行加密和校驗

 更新時間:2024年07月24日 09:47:53   作者:還不如ctrC+V  
我們在入門案例中,其實已經(jīng)是一個非常簡單的認證,但是用戶名是寫死的,密碼也需要從控制臺查看,很顯然實際中并不能這么做,下面的學習中,我們來實現(xiàn)基于內(nèi)存模型的認證以及用戶的自定義認證,密碼加密等內(nèi)容,需要的朋友可以參考下

一、密碼加密和校驗

我們在入門案例中,其實已經(jīng)是一個非常簡單的認證,但是用戶名是寫死的,密碼也需要從控制臺查看,很顯然實際中并不能這么做。下面的學習中,我們來實現(xiàn)基于內(nèi)存模型的認證以及用戶的自定義認證,密碼加密等內(nèi)容。

1.基于內(nèi)存模型實現(xiàn)認證

基于內(nèi)存模型的意思就是,我們可以現(xiàn)在內(nèi)存來構建用戶數(shù)據(jù)完成認證的操作

2.修改配置類 SecurityConfig,添加兩個bean的配置

@Bean
PasswordEncoder passwordEncoder() {
    return NoOpPasswordEncoder.getInstance();
}
 
@Bean
public UserDetailsService users() {
    UserDetails user = User.builder()
            .username("user")
            .password("123456")
            .roles("USER")
            .build();
    UserDetails admin = User.builder()
            .username("admin")
            .password("112233")
            .roles("USER", "ADMIN")
            .build();
    return new InMemoryUserDetailsManager(user, admin);
}
  • passwordEncoder()方法來說明用戶認證密碼的校驗方式,目前的設置為使用明文進行密碼校驗
  • users方法:Spring Security 提供了一個 UserDetails 的實現(xiàn)類 User,用于用戶信息的實例表示。另外,User 提供 Builder 模式的對象構建方式。

測試

可以輸入在內(nèi)存構建的用戶進行登錄,比如:user/123456 admin/112233

二、BCrypt密碼加密

明文密碼肯定不安全,所以我們需要實現(xiàn)一個更安全的加密方式BCrypt。

BCrypt就是一款加密工具,可以比較方便地實現(xiàn)數(shù)據(jù)的加密工作。也可以簡單理解為它內(nèi)部自己實現(xiàn)了隨機加鹽處理。例如,使用MD5加密,每次加密后的密文其實都是一樣的,這樣就方便了MD5通過大數(shù)據(jù)的方式進行破解。

BCrypt生成的密文長度是60,而MD5的長度是32。

我們現(xiàn)在隨便找個類,寫個main方法測試一下

package com.zzyl.vo;
 
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.util.DigestUtils;
 
public class PswdTest {
 
    public static void main(String[] args) {
 
        //md5加密
        String md5Pswd1 = DigestUtils.md5DigestAsHex("123456".getBytes());
        String md5Pswd2 = DigestUtils.md5DigestAsHex("123456".getBytes());
        System.out.println(md5Pswd1);
        System.out.println(md5Pswd2);
        System.out.println(md5Pswd1.equals(md5Pswd2));
 
        System.out.println("-------------------------------------");
 
        String password1 = BCrypt.hashpw("123456", BCrypt.gensalt());
        String password2 = BCrypt.hashpw("123456", BCrypt.gensalt());
        System.out.println(password1);
        System.out.println(password2);
        System.out.println(password1.equals(password2));
    }
}

輸出的結果如下:

e10adc3949ba59abbe56e057f20f883e
e10adc3949ba59abbe56e057f20f883e
true
-------------------------------------
$2a$10$rkB/70Cz5UvsE7F5zsBh8O2EYDoGus3/AnVrEgP5cTpsGLxM8iyG6
$2a$10$QIefMa.FmFIb2k2S9/jO7e1S3b0aeXCMtGS/ArKUyt6q28deYQrfy
false
  • md5對于同一個字符串加密多次都是相同的

  • BCrypt對于同一個字符串加密多次是不同的,主要是因為添加了隨機鹽(隨機字符串),更加安全

其中BCrypt提供了一個方法,用于驗證密碼是否正確

boolean checkpw = BCrypt.checkpw("123456", "$2a$10$rkB/70Cz5UvsE7F5zsBh8O2EYDoGus3/AnVrEgP5cTpsGLxM8iyG6");
  • 返回值為true,表示密碼匹配成功

  • 返回值為false,表示密碼匹配失敗

接下來,我們看代碼如何實現(xiàn)

1.修改配置類SecurityConfig 的passwordEncoder實現(xiàn)類為BCryptPasswordEncoder

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

PasswordEncoder的實現(xiàn)類BCryptPasswordEncoder,用于BCrypt密碼的解析。

2.修改配置類SecurityConfig 的users方法中的密碼,為加密后的密碼

@Bean
public UserDetailsService users() {
    UserDetails user = User.builder()
            .username("user")
            .password("$2a$10$2VCyByZ5oeiXCEN73wvBB.xpmJgPBbZVS/Aallmdyij2G7hmAKQTG")
            .roles("USER")
            .build();
    UserDetails admin = User.builder()
            .username("admin")
            .password("$2a$10$cRH8iMMh6XO0T.ssZ/8qVOo8ThWs/qfntIH3a7yfpbPd05h9ZGx8y")
            .roles("USER", "ADMIN")
            .build();
    return new InMemoryUserDetailsManager(user, admin);
}

大家可以使用BCrypt對想要的字符串進行加密后填充到上面的password中

3.再次測試

輸入user,密碼為加密前的密碼,比如123456,如果登錄成功,則表示認證成功(密碼校驗也成功)

結論

到現(xiàn)在為止呢,我們就清楚了Spring Security內(nèi)部使用了BCrypt來進行加密和校驗,這種加密方式相對于MD5來說更加的安全。

三、基于數(shù)據(jù)庫實現(xiàn)認證

我們剛才的實現(xiàn)都是基于內(nèi)存來構建用戶的,在實際開發(fā)中,用戶肯定會保存到數(shù)據(jù)庫中,在Spring Security框架中提供了一個UserDetailsService 接口

它的主要作用是提供用戶詳細信息。具體來說,當用戶嘗試進行身份驗證時,UserDetailsService 會被調用,以獲取與用戶相關的詳細信息。這些詳細信息包括用戶的用戶名、密碼、角色等

1、執(zhí)行流程

新創(chuàng)建一個UserDetailsServiceImpl,讓它實現(xiàn)UserDetailsService ,代碼如下

@Component
public class UserDetailsServiceImpl  implements UserDetailsService {
 
 
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
 
        //查詢數(shù)據(jù)庫中的用戶,并且返回框架要求的UserDetails 
        return null;
    }
}
  • 當前對象需要讓spring容器管理,所以在類上添加注解@Component

  • 大家注意一下loadUserByUsername方法的返回值,叫做UserDetails,這也是框架給提供了保存用戶的類,并且也是一個接口,如果我們有自定義的用戶信息存儲,可以實現(xiàn)這個接口,我們后邊會詳細講解

既然以上能使用這個類來查詢用戶信息,那么我們之前在SecurityConfig中定義的用戶信息,可以注釋掉了,如下:

    /*
    @Bean
    public UserDetailsService users() {
        UserDetails user = User.builder()
                .username("user")
                .password("$2a$10$2VCyByZ5oeiXCEN73wvBB.xpmJgPBbZVS/Aallmdyij2G7hmAKQTG")
                .roles("USER")
                .build();
        UserDetails admin = User.builder()
                .username("admin")
                .password("$2a$10$cRH8iMMh6XO0T.ssZ/8qVOo8ThWs/qfntIH3a7yfpbPd05h9ZGx8y")
                .roles("USER", "ADMIN")
                .build();
        return new InMemoryUserDetailsManager(user, admin);
    }*/

2 、數(shù)據(jù)庫查詢用戶

我們下面就來實現(xiàn)數(shù)據(jù)庫去查詢用戶,我們可以直接使用我們項目中的用戶表,實現(xiàn)的步驟如下:

  • 導入相關依賴(數(shù)據(jù)庫、mybaits、lombok等)

  • 添加配置:連接數(shù)據(jù)庫、mybatis配置等(application.yml)

  • 編寫實體類和mapper

  • 改造UserDetailsServiceImpl(用戶從數(shù)據(jù)庫中獲取)

1.pom文件添加依賴

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.1</version>
</dependency>
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.0</version>
</dependency>
<!--MySQL支持-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.19</version>
</dependency>

2.application.yml添加數(shù)據(jù)庫相關配置

#服務配置
server:
  #端口
  port: 8080
spring:
  application:
    name: springsecurity-demo
  #數(shù)據(jù)源配置
  datasource:
    druid:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://192.168.200.146:3306/security_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
      username: root
      password: heima123
# MyBatis配置
mybatis:
  #mapper配置文件
  mapper-locations: classpath*:mapper*/*Mapper.xml
  type-aliases-package: com.itheima.project.entity
  configuration:
    # 這個配置會將執(zhí)行的sql打印出來,在開發(fā)或測試的時候可以用
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    # 駝峰下劃線轉換
    map-underscore-to-camel-case: true
    use-generated-keys: true
    default-statement-timeout: 60
    default-fetch-size: 100

3.表結構及實體類和mapper

新創(chuàng)建一個數(shù)據(jù)庫,名字為:security_db

導入當天資料的sql腳本

用戶實體類

package com.itheima.project.entity;
 
import lombok.Data;
 
import java.time.LocalDateTime;
 
@Data
public class User {
 
    public Long id;
 
    /**
     * 用戶賬號
     */
    private String username;
 
    /**
     * 密碼
     */
    private String password;
 
    /**
     * 用戶昵稱
     */
    private String nickName;
 
}

用戶mapper,我們只需要定義一個根據(jù)用戶名查詢的方法即可

package com.itheima.project.mapper;
 
import com.itheima.project.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
 
/**
 * @author sjqn
 */
@Mapper
public interface UserMapper {
 
    @Select("select * from sys_user where username = #{username}")
    public User findByUsername(String username);
}
  • 改造UserDetailsServiceImpl
package com.zzyl.security.service;
 
import com.zzyl.security.entity.User;
import com.zzyl.security.entity.UserAuth;
import com.zzyl.security.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
 
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.SimpleTimeZone;
 
/**
 * @author sjqn
 */
@Component
public class UserDetailsServiceImpl implements UserDetailsService {
 
 
    @Autowired
    private UserMapper userMapper;
 
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
 
        //查詢用戶
        User user = userMapper.findByUsername(username);
        if(user == null){
            throw new RuntimeException("用戶不存在或已被禁用");
        }
        SimpleGrantedAuthority user_role = new SimpleGrantedAuthority("user");
        SimpleGrantedAuthority admin_role = new SimpleGrantedAuthority("admin");
        List<GrantedAuthority> list = new ArrayList<GrantedAuthority>();
 
        list.add(user_role);
        list.add(admin_role);
 
        return new org.springframework.security.core.userdetails.User(user.getUsername()
                ,user.getPassword()
                , list);
    }
}
  • 自定義UserDetails

上述代碼中,返回的UserDetails或者是User都是框架提供的類,我們在項目開發(fā)的過程中,很多需求都是我們自定義的屬性,我們需要擴展該怎么辦?

其實,我們可以自定義一個類,來實現(xiàn)UserDetails,在自己定義的類中,就可以擴展自己想要的內(nèi)容,如下代碼:

package com.zzyl.security.entity;
 
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
 
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
 
/**
 * @author sjqn
 * @date 2023/9/1
 */
@Data
public class UserAuth implements UserDetails {
 
    private String username; //固定不可更改
    private String password;//固定不可更改
    private String nickName;  //擴展屬性  昵稱
    private List<String> roles; //角色列表
 
 
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        if(roles==null) return null;
        //把角色類型轉換并放入對應的集合
        return roles.stream().map(role -> new SimpleGrantedAuthority("ROLE_"+role)).collect(Collectors.toList());
    }
 
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
 
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }
 
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
 
    @Override
    public boolean isEnabled() {
        return true;
    }
}

然后,我們可以繼續(xù)改造UserDetailsServiceImpl中檢驗用戶的邏輯,代碼如下:

package com.itheima.project.service;
 
import com.itheima.project.entity.User;
import com.itheima.project.mapper.UserMapper;
import com.itheima.project.vo.UserAuth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
 
import java.util.ArrayList;
import java.util.List;
 
/**
 * @author sjqn
 */
@Component
public class UserDetailServiceImpl implements UserDetailsService {
 
    @Autowired
    private UserMapper userMapper;
 
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //查詢用戶
        User user = userMapper.findByUsername(username);
        if(user == null){
            throw new RuntimeException("用戶不存在或已被禁用");
        }
        UserAuth userAuth = new UserAuth();
        userAuth.setUsername(user.getUsername());
        userAuth.setPassword(user.getPassword());
        userAuth.setNickName(user.getNickName());
 
        //添加角色
        List<String> roles=new ArrayList<>();
        if("user@qq.com".equals(username)){
            roles.add("USER");
            userAuth.setRoles(roles);
        }
        if("admin@qq.com".equals(username)){
            roles.add("USER");
            roles.add("ADMIN");
            userAuth.setRoles(roles);
        }
        return userAuth;
    }
}

修改HelloController,使用getPrincipal()方法讀取認證主體對象。

/**
 * @ClassName
 * @Description
 */
@RestController
public class HelloController {
 
    @RequestMapping("/hello")
    public String hello(){
        //獲取當前登錄用戶名稱
        String name = SecurityContextHolder.getContext().getAuthentication().getName();
        UserAuth userAuth = (UserAuth)SecurityContextHolder.getContext().getAuthentication().getPrincipal();//取出認證主體對象
 
        return "hello :"+name+"  昵稱:"+userAuth.getNickName();
    }
 
}

測試

重啟項目之后,可以根據(jù)數(shù)據(jù)庫中有的用戶進行登錄,如果登錄成功則表示整合成功

以上就是基于Spring Security實現(xiàn)對密碼進行加密和校驗的詳細內(nèi)容,更多關于Spring Security密碼加密和校驗的資料請關注腳本之家其它相關文章!

相關文章

  • Java rmi遠程方法調用基本用法解析

    Java rmi遠程方法調用基本用法解析

    這篇文章主要介紹了Java rmi遠程方法調用基本用法解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-05-05
  • springboot項目實現(xiàn)配置跨域

    springboot項目實現(xiàn)配置跨域

    這篇文章主要介紹了springboot項目實現(xiàn)配置跨域問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-09-09
  • Spring boot整合Mybatis-plus過程解析

    Spring boot整合Mybatis-plus過程解析

    這篇文章主要介紹了Spring boot整合Mybatis-plus過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-03-03
  • Java文件字符輸入流FileReader讀取txt文件亂碼的解決

    Java文件字符輸入流FileReader讀取txt文件亂碼的解決

    這篇文章主要介紹了Java文件字符輸入流FileReader讀取txt文件亂碼的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java單例模式簡單介紹

    Java單例模式簡單介紹

    這篇文章主要為大家詳細介紹了Java單例模式簡單的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • Java中try catch處理異常示例

    Java中try catch處理異常示例

    這篇文章主要給大家介紹了關于Java中try catch 的基本用法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-12-12
  • java Unicode和UTF-8之間轉換實例

    java Unicode和UTF-8之間轉換實例

    這篇文章主要介紹了java Unicode和UTF-8之間轉換實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • 使用java代碼實現(xiàn)一個月內(nèi)不再提醒,通用到期的問題

    使用java代碼實現(xiàn)一個月內(nèi)不再提醒,通用到期的問題

    這篇文章主要介紹了使用java代碼實現(xiàn)一個月內(nèi)不再提醒,通用到期的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • 兩種用空格分隔的java字符串的方式

    兩種用空格分隔的java字符串的方式

    這篇文章主要介紹了兩種用空格分隔的java字符串的方式的方法,非常簡單實用,需要的朋友可以參考下
    2015-03-03
  • Java實現(xiàn)帶頭結點的單鏈表

    Java實現(xiàn)帶頭結點的單鏈表

    這篇文章主要為大家詳細介紹了Java實現(xiàn)帶頭結點的單鏈表,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-09-09

最新評論