精华内容
下载资源
问答
  • 博客学习目标 1、用户注册时候,对数据库中用户的密码进行加密存储(使用 ...密码应该通过哈希算法进行加密。 有很多标准的算法比如SHA或者MD5,结合salt(盐)一个不错的选择。 Spring Security 提供了BCryptPasswor...

    博客学习目标

    1、用户注册时候,对数据库中用户的密码进行加密存储(使用 SpringSecurity)。
    2、使用 JWT 鉴权认证。

    一、BCrypt 密码加密

    1、常见的加密方式

    任何应用考虑到安全,绝不能明文的方式保存密码。密码应该通过哈希算法进行加密。 有很多标准的算法比如SHA或者MD5,结合salt(盐)是一个不错的选择。 Spring Security 提供了BCryptPasswordEncoder类,实现Spring的PasswordEncoder接口使用BCrypt强哈希方法来加密数据库中用户的密码。BCrypt强哈希方法 每次加密的结果都不一样。

    2、是骡子是马拉出来遛遛(代码案例演示)

    技术栈:SpringBoot 2.1.6.RELEASE(数据访问层使用 JPA)
    开发工具:IDEA、Java8、Postman
    引入依赖
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!-- 引入 SpringSecurity --> 
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <!-- lombok工具 -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    控制层 controller
    @RestController
    @CrossOrigin
    @RequestMapping("/user")
    public class UserController {
    
        @Autowired
        private UserService userService;
    
        // 用户注册
        @RequestMapping(value = "/register", method = RequestMethod.POST)
        public Result register(@RequestBody User user) {
    
            boolean isRegister = userService.register(user);
    
            if (!isRegister) {
                return new Result(false, StatusCode.ERROR, "手机号码已经被注册,请直接登陆!");
            }
    
            return new Result(true, StatusCode.OK, "注册成功!");
        }
    
        // 用户登陆(限定使用手机号和密码登录)
        @RequestMapping(value = "/login", method = RequestMethod.POST)
        public Result login(@RequestBody User user) {
    
            User loginUser = userService.login(user.getMobile(), user.getPassword());
    
            if (null == loginUser) {
                return new Result(false, StatusCode.LOGINERROR, "登陆失败,请检查手机号或者密码是否正确.");
            }
    
            return new Result(true, StatusCode.OK, "登陆成功.");
        }
    }
    业务处理层 service
    @Service
    public class UserService {
    
        @Autowired
        private UserDao userDao;
    
        @Autowired
        private BCryptPasswordEncoder encoder;
    
        // 用户注册功能
        public boolean register(User user) {
    
            User existUser = userDao.findByMobile(user.getMobile());
    
            if (null == existUser) {
                user.setId(UUIDUtil.getUUID())
                        .setPassword(encoder.encode(user.getPassword()))    // 密码加密
                        .setFollowcount(0)
                        .setFanscount(0)
                        .setOnline(0L)
                        .setRegdate(new Date())
                        .setUpdatedate(new Date())
                        .setLastdate(new Date());
    
                userDao.save(user);
    
                return true;
            }
    
            return false;
    
        }
    
        // 用户登陆(限定使用手机号和密码登录)
        public User login(String mobile, String password) {
    
            User existUser = userDao.findByMobile(mobile);
    
            if (null != existUser && encoder.matches(password, existUser.getPassword())) {
    
                return existUser;
            }
    
            return null;
        }
    }
    数据库访问层 dao
    public interface UserDao extends JpaRepository<User, String>, JpaSpecificationExecutor<User> {
    
        // 判断用户手机号是否已经注册
        User findByMobile(String mobile);
    }
    启动类注入 BCryptPasswordEncoder
    @SpringBootApplication
    public class BcryptJwtApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(BcryptJwtApplication.class, args);
        }
    
        @Bean
        public BCryptPasswordEncoder bCryptPasswordEncoder() {
            return new BCryptPasswordEncoder();
        }
    }
    SpringSecurity 安全配置类,对路径拦截。
    @Configuration
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        //authorizeRequests 所有 security 全注解配置实现的开端,表示开始说明需要的权限
        //需要的权限分两部分,第一部分是拦截的路径,第二部分访问该路径需要的权限
        //antMarcher表示拦截说明路径,permitAll任何权限都可以访问,直接放行所有
        //anyRequest()任何请求,authenticated认证后才能访问
        //.and.csrf.disable(),固定写法,表示使用csrf拦截失败
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers("/**").permitAll()
                    .anyRequest().authenticated()
                    .and().csrf().disable();
        }
    }
    使用 Postman 发送用户注册请求(如下图),在查询数据库可看到用户密码已加密。

    ea75582a4433c33011988398d6180ec2.png
    使用 Postman 发送用户登陆请求(如下图),返回登陆成功提示。

    35c0374cde545ae164ee3a6ec5087b8a.png
    全部示例代码已经上传到 github ,文末可获取地址。

    二、常见的认证机制

    2.1、HTTP Basic Auth

    HTTP Basic Auth简单点说就是每次请求API时都提供用户的username和 password,简言之,Basic Auth是配合RESTful API 使用的最简单的认证方式,只需提供 用户名密码即可,但由于有把用户名密码暴露给第三方客户端的风险,在生产环境下被 使用的越来越少。因此,在开发对外开放的RESTful API时,尽量避免采用HTTP Basic Auth

    2.2 Cookie Auth

    Cookie认证机制就是为一次请求认证在服务端创建一个Session对象,同时在客户端 的浏览器端创建了一个Cookie对象;通过客户端带上来Cookie对象来与服务器端的 session对象匹配来实现状态管理的。默认的,当我们关闭浏览器的时候,cookie会被删 除。但可以通过修改cookie 的expire time使cookie在一定时间内有效;

    2.3 OAuth

    OAuth(开放授权)是一个开放的授权标准,允许用户让第三方应用访问该用户在 某一web服务上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和 密码提供给第三方应用。
    OAuth允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提 供者的数据。每一个令牌授权一个特定的第三方系统(例如,视频编辑网站)在特定的时 段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这 样,OAuth让用户可以授权第三方网站访问他们存储在另外服务提供者的某些特定信 息,而非所有内容。
    下面是OAuth2.0的流程:

    4a3ceef30877a94ff6582e64e6f4a8cc.png


    这种基于OAuth的认证机制适用于个人消费者类的互联网产品,如社交类APP等应 用,但是不太适合拥有自有认证权限管理的企业应用。

    2.4 Token Auth

    使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程如下: 1. 客户端使用用户名跟密码请求登录。 2. 服务端收到请求,去验证用户名与密码。 3. 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端。 4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里。 5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token。 6. 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向 客户端返回请求的数据。
    下面是Token Auth 的流程:

    db988fc5434d55c371deb20c7c3faa02.png

    重点:Token机制相对于Cookie机制的优缺点?

    • 支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提 是传输的用户认证信息通过HTTP头传输.
    • 无状态(也称:服务端可扩展行):Token机制在服务端不需要存储session信息,因为 Token 自身包含了所有登录用户的信息,只需要在客户端的cookie或本地介质存储 状态信息.
    • 更适用CDN: 可以通过内容分发网络请求你服务端的所有资料(如:javascript, HTML,图片等),而你的服务端只要提供API即可.
    • 去耦: 不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在 你的API被调用的时候,你可以进行Token生成调用即可.
    • 更适用于移动应用: 当你的客户端是一个原生平台(iOS, Android,Windows 8等) 时,Cookie是不被支持的(你需要通过Cookie容器进行处理),这时采用Token认 证机制就会简单得多。
    • CSRF:因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防 范。
    • 性能: 一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256 计算 的Token验证和解析要费时得多.
    • 不需要为登录页面做特殊处理: 如果你使用Protractor 做功能测试的时候,不再需要 为登录页面做特殊处理.

    三、什么是 JSON Web Token(JWT)

    JWT 格式组成:头部+载荷+签名 ( header + payload + signature )

    头部(Header)

    头部用于描述关于该 JWT 的最基本的信息,例如其类型以及签名所用的算法等。可以被表示成一个 JSON 对象。例如以下在头部指明了签名算法是HS256算法。我们进行BASE64编码以下内容:{"typ":"JWT","alg":"HS256"},得到编码后的字符串如下:JTdCJTIydHlwJTIyJTNBJTIySldUJTIyJTJDJTIyYWxnJTIyJTNBJTIySFMyNTYlMjIlN0Q=
    小知识:Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2 的6次方等于64,所以每6个比特为一个单元,对应某个可打印字符。三个字节有24 个比特,对应于4个Base64单元,即3个字节需要用4个可打印字符来表示。JDK 中 提供了非常方便的 BASE64Encoder 和 BASE64Decoder,用它们可以非常方便的 完成基于 BASE64 的编码和解码。

    载荷(playload)

    载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分:
    (1) 标准中注册的声明(建议但不强制使用)
    • iss: jwt签发者。
    • sub: jwt所面向的用户。
    • aud: 接收jwt的一方 。
    • exp: jwt的过期时间,这个过期时间必须要大于签发时间 。
    • nbf: 定义在什么时间之前,该jwt都是不可用的.。
    • iat: jwt的签发时间 。
    • jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
    (2) 公共的声明
    公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息. 但不建议添加敏感信息,因为该部分在客户端可解密。
    (3) 私有声明
    私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64 是对称解密的,意味着该部分信息可以归类为明文信息。
    定义一个payload: {"sub":"1234567890","name":"John Doe","admin":true},然后将其进行base64编码,得到 Jwt 的第二部分如下:JTdCJTIyc3ViJTIyJTNBJTIyMTIzNDU2Nzg5MCUyMiUyQyUyMm5hbWUlMjIlM0ElMjJKb2huJUEwRG9lJTIyJTJDJTIyYWRtaW4lMjIlM0F0cnVlJTdE

    签名(signature)

    jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
    header (base64后的) 。
    payload (base64后的)。
    secret。
    这个部分需要base64加密后的header和base64加密后的payload使用,连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分如下:(就是使用头部指明的签名算法对已经加密了以后的字符串在进行加密得到第三部分)TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
    将这三部分用连接成一个完整的字符串,构成了最终的jwt如下:JTdCJTIydHlwJTIyJTNBJTIySldUJTIyJTJDJTIyYWxnJTIyJTNBJTIySFMyNTYlMjIlN0Q=.JTdCJTIyc3ViJTIyJTNBJTIyMTIzNDU2Nzg5MCUyMiUyQyUyMm5hbWUlMjIlM0ElMjJKb2huJUEwRG9lJTIyJTJDJTIyYWRtaW4lMjIlM0F0cnVlJTdE.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

    知识点1:

    Signature 部分是对前两部分的签名,防止数据篡改。首先需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后使用 Header 里面指定的签名算法,按照下面的公式产生签名HMACSHA256(base64UrlEncode(header) + “.” + base64UrlEncode(payload), secret)

    算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用(.)分隔,就可以返回给用户。

    知识点2:

    secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。

    四、案例代码演示

    在上面代码基础上继续演示
    需求:删除用户(User),必须拥有管理员(Admin)权限,否则不能删除。
    前后端约定:前端请求后端时需要添加头信息 Authorization ,内容为Bearer+空格 +token
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.6.0</version>
    </dependency>
    用户生成 、解析 token 的工具类
    @ConfigurationProperties("jwt.config")
    public class JwtUtil {
    
        private String key;
        private long ttl;//一个小时
    
        public String getKey() {return key;}
        public void setKey(String key) {this.key = key;}
        public long getTtl() {return ttl;}
        public void setTtl(long ttl) {this.ttl = ttl;}
    
        // 生成JWT
        public String createJWT(String id, String subject, String roles) {
            long nowMillis = System.currentTimeMillis();
            Date now = new Date(nowMillis);
            JwtBuilder builder = Jwts.builder().setId(id)
                    .setSubject(subject)
                    .setIssuedAt(now)
                    .signWith(SignatureAlgorithm.HS256, key).claim("roles", roles);
            if (ttl > 0) {
                builder.setExpiration(new Date(nowMillis + ttl));
            }
            return builder.compact();
        }
    
        // 解析JWT
        public Claims parseJWT(String jwtStr) {
            return Jwts.parser()
                    .setSigningKey(key)
                    .parseClaimsJws(jwtStr)
                    .getBody();
        }
    
    }
    启动类注入 JwtUtil 工具类
    @SpringBootApplication
    public class BcryptJwtApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(BcryptJwtApplication.class, args);
        }
    
        @Bean
        public JwtUtil jwtUtil() {
            return new JwtUtil();
        }
    
    }
    创建拦截器类
    如果每个方法都去写一段代码验证用户登陆 token 的正确性,冗余度太高不利于维护。我们可以将这段代码放入拦截器去实现同意拦截,再判断用户 token。
    Spring为我提供了 org.springframework.web.servlet.handler.HandlerInterceptorAdapter 这个适配器, 继承此类,可以非常方便的实现自己的拦截器。
    他有三个方法: 分别实现预处理、后处理(调用了Service并返回ModelAndView,但未进行页面渲 染)、返回处理(已经渲染了页面)。
    在preHandle中,可以进行编码、安全控制等处理;
    在postHandle中,有机会修改ModelAndView;
    在afterCompletion中,可以根据ex是否为null判断是否发生了异常,进行日志记录。
    @Component
    public class JwtInterceptor extends HandlerInterceptorAdapter {
    
        @Autowired
        private JwtUtil jwtUtil;
    
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    
            System.out.println("经过拦截器");
    
            final String authHeader = request.getHeader("Authorization");//获取头信息
            if (authHeader != null && authHeader.startsWith("Bearer ")) {   // 注意是 Bearer + 空格
                final String token = authHeader.substring(7);
                Claims claims = jwtUtil.parseJWT(token);
                if (claims != null) {
                    if ("admin".equals(claims.get("roles"))) {//如果是管理员
                        request.setAttribute("admin_claims", claims);
                    }
                    if ("user".equals(claims.get("roles"))) {//如果是普通用户
                        request.setAttribute("user_claims", claims);
                    }
                }
            }
    
            return true;
        }
    }
    配置拦截器类
    @Configuration
    public class ApplicationConfig extends WebMvcConfigurationSupport {
    
        @Autowired
        private JwtInterceptor jwtInterceptor;
    
        protected void addInterceptors(InterceptorRegistry registry) {
    
            registry.addInterceptor(jwtInterceptor)
                    .addPathPatterns("/**")
                    .excludePathPatterns("/**/login");
        }
    }
    控制层 controller
    @RestController
    @CrossOrigin
    @RequestMapping("/admin")
    public class AdminController {
    
        @Autowired
        private AdminService adminService;
    
        @Autowired
        private JwtUtil jwtUtil;
    
        // Admin 用户登陆
        @RequestMapping(value = "/login", method = RequestMethod.POST)
        public Result login(@RequestBody Admin admin) {
    
            Admin loginUser = adminService.findByLoginNameAndPassword(admin.getLoginname(), admin.getPassword());
    
            if (null == loginUser) {
                return new Result(false, StatusCode.LOGINERROR, "登陆失败,请检查用户名或者密码是否正确");
            }
    
            // 生成令牌,并且返回给前台
            String token = jwtUtil.createJWT(loginUser.getId(), loginUser.getLoginname(), "admin");
            Map<String, Object> map = new HashMap<>();
            map.put("token", token);
            map.put("role", "admin");
            map.put("name", loginUser.getLoginname());
    
            return new Result(true, StatusCode.OK, "登陆成功", map);
        }
    
        // 添加 Admin 用户
        @RequestMapping(value = "/add", method = RequestMethod.POST)
        public Result add(@RequestBody Admin admin) {
            adminService.add(admin);
            return new Result(true, StatusCode.OK, "增加成功");
        }
    }
    业务处理层 service
    @Service
    public class AdminService {
    
        @Autowired
        private AdminDao adminDao;
    
        @Autowired
        private BCryptPasswordEncoder encoder;
    
        // 根据登陆用户名和密码查询
        public Admin findByLoginNameAndPassword(String loginName, String password) {
    
            Admin admin = adminDao.findByLoginname(loginName);
            if (null != admin && encoder.matches(password, admin.getPassword())) {
                return admin;
            }
    
            return null;
        }
    
        // 添加管理员
        public void add(Admin admin) {
            admin.setId(UUIDUtil.getUUID());    // 主键
            // 密码加密
            String newPassword = encoder.encode(admin.getPassword());
            admin.setPassword(newPassword);
            adminDao.save(admin);
        }
    
    }
    数据访问层 dao
    public interface AdminDao extends JpaRepository<Admin, String>, JpaSpecificationExecutor<Admin> {
    
        // 管理员登陆校验
        Admin findByLoginname(String loginName);
    }
    修改UserController的delete方法
    @RestController
    @CrossOrigin
    @RequestMapping("/user")
    public class UserController {
    
        @Autowired
        private UserService userService;
    
        @Autowired
        private HttpServletRequest servletRequest;
    
        /**
         * 删除:删除用户,必须拥有管理员权限,否则不能删除
         * <p>
         * 前后端约定:前端请求微服务时需要添加头信息Authorization ,内容为Bearer+空格+token
         *
         * @param id
         */
        @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
        public Result delete(@PathVariable String id) {
    
            Claims claims = (Claims) servletRequest.getAttribute("admin_claims");
            if (null == claims) {
                return new Result(true, StatusCode.ACCESSERROR, "无权访问");
            }
            userService.deleteById(id);
            return new Result(true, StatusCode.OK, "删除成功");
        }
    
    }
    测试生成 token 步骤
    1、和上面一样使用 Postman 注册一个 Admin 账户
    2、使用 Postman 模拟访问登陆,看是否返回 token
    3、在使用 Bearer+空格+token,放入头部删除用户,看是否删除成功。

    源码地址

    GitHub地址: https://github.com/RookieMZL/practice-sample/tree/dev/bcrypt-jwt
    欢迎大家指教,提出意见。
    展开全文
  • 本次写的内容不是shiro框架怎么计算hash值的,仅仅进行使用、 首先声明,本次的加盐的加密方法不可逆的。 首先引入包。 import org.apache.shiro.crypto.hash.SimpleHash; import org.apache.shiro.util....

    本次写的内容不是shiro框架怎么计算hash值的,仅仅是进行使用、

    首先声明,本次的加盐的加密方法是不可逆的。

    首先引入包。

    import org.apache.shiro.crypto.hash.SimpleHash;
    import org.apache.shiro.util.ByteSource;

    第一个为shiro中的简单哈希的类,

    第二个为shiro中的获取字节数组的类。

    下图为本次要使用到的SimpleHash的构造器。四个参数,分别

    algorithmName代表进行加密的算法名称、

    source代表需要加密的元数据,如密码、

    salt代表盐,需要加进一起加密的数据、

    hashIterations代表hash迭代次数。

    测试代码如下、

    测试中加的盐salt就是用户的姓名。

    public class PasswordHelper {
    	
    	private String algorithmName = "md5";
    	private int hashIterations = 2;
    
    	public void encryptPassword(UserEntity user) {
    		String newPassword = new SimpleHash(algorithmName, user.getPassWord(),
    				ByteSource.Util.bytes(user.getUserName()), hashIterations).toHex();
    		user.setPassWord(newPassword);
    
    	} 
    
    	/**
    	 * 测试使用
    	 */
    	public static void main(String[] args) {
    		PasswordHelper passwordHelper = new PasswordHelper();
    		UserEntity user = new UserEntity();
    		user.setUserName("潘亚茹");
    		user.setPassWord("123456");
    		passwordHelper.encryptPassword(user);
    		System.out.println(user);
    	}
    }

    输出数据如下、

    userName=潘亚茹, passWord=0fd20118436982b58e93a61771c61d01

    附坐标:

    <!-- cas-shiro -->
    		<dependency>
    			<groupId>org.apache.shiro</groupId>
    			<artifactId>shiro-spring</artifactId>
    			<version>1.2.4</version>
    		</dependency>
    		<dependency>
    			<groupId>org.apache.shiro</groupId>
    			<artifactId>shiro-ehcache</artifactId>
    			<version>1.2.4</version>
    		</dependency>
    		<dependency>
    			<groupId>org.apache.shiro</groupId>
    			<artifactId>shiro-cas</artifactId>
    			<version>1.2.4</version>
    		</dependency> 

     

    展开全文
  • Bcrypt一个跨平台的文件加密工具。 为了保护用户的明文密码不被泄露,一般会对密码进行单向不可逆加密...那么怎么使用呢?这里我用node的项目演示。 首先引入Bcrypt yarn add bcrypt 这一个用户注册时输入的...

    Bcrypt是一个跨平台的文件加密工具。

    为了保护用户的明文密码不被泄露,一般会对密码进行单向不可逆加密——哈希。
    而Bcrypt恰恰就做到这一点,通过Bcrypt加密的明文密码即使解密也不是真的“解密”,哪怕是内部人员,也不会看到密码。
    这大大的提高了用户的安全级别。那么怎么使用呢?这里我用node的项目演示。

    首先引入Bcrypt

    yarn add bcrypt

    这是一个用户注册时输入的密码

    if (isSigned) {
        res.render('user', {
          ret: true,
          data: JSON.stringify({
            msg: '用户名已经存在!'
          })
        })
      // 当用户没有注册时,首先将密码加密,再将用户名和加密后的密码入库
      } else {
        let result = await userModel.signup({
          username,
          password: await _doCrypto(password)
        })
      }
     
    //将从前端接受到的password进行加密
    const _doCrypto = (password) => {
      return new Promise((resolve) => {
      //这里的salt值,每次都是不一样的,也是根据取到不同的salt,所以每次的加密结果都不一样
        bcrypt.genSalt(10, function (err, salt) {
          bcrypt.hash(password, salt, function (err, hash) {
            resolve(hash)
          });
        });
      })
    }

    登录时我们可以这样进行验证

    //密码认证
    let isCorrect = await _comparePwd(password, result.password)
     
    //通过_comparePwd方法将用户输入的明文与数据的加密过的进行比对
    const _comparePwd = (fromUser, fromDatabase) => {
      return new Promise((resolve) => {
        bcrypt.compare(fromUser, fromDatabase, (err, res) => {
          resolve(res)
        })
      })
    }

    为了系统的安全性与用户的体验,使用bcrypt加密工具还是必不可少的

    展开全文
  • 对等加密的TCP服务器 该项目的目的为多个客户端建立基于TCP的服务器,这些客户端之间可以相互发送和接收消息。 如何编译? g++ server.cpp -o server -lpthread -lsqlite3 g++ client.cpp -o client -lpthread -...
  • Bcrypt一个跨平台的文件加密工具。为了保护用户的明文密码不被泄露,一般会对密码进行单向不可逆...那么怎么使用呢?这里我用node的项目演示。首先引入Bcryptyarn add bcrypt这一个用户注册时输入的密码if (isS...

    Bcrypt是一个跨平台的文件加密工具。

    为了保护用户的明文密码不被泄露,一般会对密码进行单向不可逆加密——哈希。

    而Bcrypt恰恰就做到这一点,通过Bcrypt加密的明文密码即使解密也不是真的“解密”,哪怕是内部人员,也不会看到密码。

    这大大的提高了用户的安全级别。那么怎么使用呢?这里我用node的项目演示。

    首先引入Bcrypt

    yarn add bcrypt

    这是一个用户注册时输入的密码

    if (isSigned) {

    res.render('user', {

    ret: true,

    data: JSON.stringify({

    msg: '用户名已经存在!'

    })

    })

    // 当用户没有注册时,首先将密码加密,再将用户名和加密后的密码入库

    } else {

    let result = await userModel.signup({

    username,

    password: await _doCrypto(password)

    })

    }

    //将从前端接受到的password进行加密

    const _doCrypto = (password) => {

    return new Promise((resolve) => {

    //这里的salt值,每次都是不一样的,也是根据取到不同的salt,所以每次的加密结果都不一样

    bcrypt.genSalt(10, function (err, salt) {

    bcrypt.hash(password, salt, function (err, hash) {

    resolve(hash)

    });

    });

    })

    }

    登录时我们可以这样进行验证

    //密码认证

    let isCorrect = await _comparePwd(password, result.password)

    //通过_comparePwd方法将用户输入的明文与数据的加密过的进行比对

    const _comparePwd = (fromUser, fromDatabase) => {

    return new Promise((resolve) => {

    bcrypt.compare(fromUser, fromDatabase, (err, res) => {

    resolve(res)

    })

    })

    }

    为了系统的安全性与用户的体验,使用bcrypt加密工具还是必不可少的

    4f33012aba71c99de7bc303782bc3150.png
    展开全文
  • 海盗云 ... 由于压缩包经过加密的,因此重新托管您的哈希的朋友无法读取其内容。 太好了! 如果其他计算机正在重新托管您的哈希,您所需要做的就是保留~/.config/piratcloud的备份! 用法 备份资料夹
  • 先说说我平时在公司是怎么加密的吧。 首先,在创建用户密码的时候,在用户表,有一个字段是 key ,存储的是随机生成的字符串,然后在对 用户输入的密码 加 上 key 进行md5 加密 $password = $_POST['pass
  • 密码应该通过哈希算法... Spring Security 提供了BCryptPasswordEncoder类,实现Spring的PasswordEncoder接口使用BCrypt强哈希方法来加密密码。BCrypt强哈希方法 每次加密的结果都不一样。好了废话不多说,就看怎么整合
  • 对于大部分网站,密码的存储和验证... ... 项目中我们使用 hash 算法来进行密码加密保护的,hash 算法一种单项的函数,它可以把任意数量的数据转换成固定的长度的哈希值,也就是说将一个大集合映射到一...
  • MD5加密

    2020-12-11 21:32:55
    计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。广泛用于加密和解密技术,常...
  • 比特币交易涉及到很多密码学知识:公钥、私钥、哈希、对称加密、非对称加密、签名等等。那么哪些需要用户认真保管不能对外泄露的,那些需要用户公开的呢?先从钱包地址的生成说起。钱包地址生成1. 首先使用...
  • 探究:一个数据包在网络中到底是怎么游走的? 硬不硬你说了算!全图解被问千百遍的TCP三次握手和四次挥手面试题 硬核!30 张图解 HTTP 常见的面试题 如果面试再问GET和POST区别,就把这篇甩给他 计网 TCP/UDP 部分...
  • 图说区块链 读书笔记

    2021-01-08 04:49:32
    去了解拜占庭将军问题是怎么一回事。 2. 一些名词 PoW,也就是 工作量证明。比特币在区块的生成过程中使用了PoW机制。一个符合要求的区块哈希值由N个 前导零构成,零的个数取决于网络的难度值。要得到合理的区块哈希...
  • 一.什么消息摘要呢? 消息摘要一个唯一对应一个消息或文本的固定长度的值,它由一个单向的Hash加密函数对消息进行作用而产生 简单来说,它就是用来接收随意大小的数据,输出固定...怎么使用消息摘要算法? 准备
  • MD5

    2020-11-25 14:16:26
    计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。广泛用于加密和解密技术,常...
  • C#基础类库

    2018-07-11 08:45:26
    哈希加密帮助类,得到随机哈希加密字符串,随机哈希数字加密等 MySecurity MySecurity--Security安全加密/Security Base64/Security文件加密,以及一些常用的操作方法 RSACryption RSACryption--RSA加密/RSA...
  • Storm.dll MPQ文件读取

    2013-02-20 14:24:28
    但是还没完,还有一种方式,某些软件绕过mpq前面的哈希索引表,直接扫描后面的文件,这样虽然不能知道文件名,但能得到完整的文件列表(再怎么说文件也封在mpq里的吧,把mpq整个扫一遍总能发现)。例子新版...
  • MD5源码(C++)

    热门讨论 2009-09-07 19:13:52
    MD5的全称Message-digest Algorithm 5(信息-摘要算法),用于确保信息传输... MD5用的是哈希函数,在计算机网络中应用较多的不可逆加密算法有RSA公司发明的MD5算法和由美国国家技术标准研究所建议的安全散列算法SHA.
  • vc++ 应用源码包_1

    热门讨论 2012-09-15 14:22:12
    详细讲解了Crypt++的加密解密的使用以及其它的加密解密方法(例如base64加解密、哈希加解密以及其它的文件加解密),分静态库和动态库方法。 JSCalls_demo js调用的演示源码 树控件拖动 演示了在树控件中来回拖动...
  • vc++ 应用源码包_2

    热门讨论 2012-09-15 14:27:40
    详细讲解了Crypt++的加密解密的使用以及其它的加密解密方法(例如base64加解密、哈希加解密以及其它的文件加解密),分静态库和动态库方法。 JSCalls_demo js调用的演示源码 树控件拖动 演示了在树控件中来回拖动...
  • vc++ 应用源码包_6

    热门讨论 2012-09-15 14:59:46
    详细讲解了Crypt++的加密解密的使用以及其它的加密解密方法(例如base64加解密、哈希加解密以及其它的文件加解密),分静态库和动态库方法。 JSCalls_demo js调用的演示源码 树控件拖动 演示了在树控件中来回拖动...
  • vc++ 应用源码包_5

    热门讨论 2012-09-15 14:45:16
    详细讲解了Crypt++的加密解密的使用以及其它的加密解密方法(例如base64加解密、哈希加解密以及其它的文件加解密),分静态库和动态库方法。 JSCalls_demo js调用的演示源码 树控件拖动 演示了在树控件中来回拖动...
  • vc++ 应用源码包_4

    热门讨论 2012-09-15 14:38:35
    详细讲解了Crypt++的加密解密的使用以及其它的加密解密方法(例如base64加解密、哈希加解密以及其它的文件加解密),分静态库和动态库方法。 JSCalls_demo js调用的演示源码 树控件拖动 演示了在树控件中来回拖动...
  • vc++ 应用源码包_3

    热门讨论 2012-09-15 14:33:15
    详细讲解了Crypt++的加密解密的使用以及其它的加密解密方法(例如base64加解密、哈希加解密以及其它的文件加解密),分静态库和动态库方法。 JSCalls_demo js调用的演示源码 树控件拖动 演示了在树控件中来回拖动...
  • 2.4.1使用Maven 21 Maven仓库 21 Spring框架 22 2.4.2 Gradle 23 Gradle存储库 23 使用Spring 4.0.x和Gradle 24 2.4.3项目模块 25 核心 - spring-security-core.jar 25 远程处理 - spring-security-remoting.jar 25 ...
  • D系列:与编码(Decode)相关的demo,加密哈希相关的也会放在这里。 序号 工程名称 说明 D01 cjson_app 使用cJSON示例 D02 base64_app base64编码示例 D03 md5_app ESP8266使用MD5进行Hash H系列:...

空空如也

空空如也

1 2
收藏数 28
精华内容 11
关键字:

哈希加密是怎么使用的