首页 > 其他分享 >SpringBoot 实现密码加密以及登录成功token实现

SpringBoot 实现密码加密以及登录成功token实现

时间:2022-12-02 16:24:46浏览次数:61  
标签:username map 加密 SpringBoot token put import String

谨以此文章记录自己的学习过程,借以帮助有同样需求的小伙伴,实现的不完善,只是将大概的主要内容实现而已~

一、demo所需的技术

springBoot、springSecurity、mysql、lombok

部分依赖pom.xml

<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-core</artifactId>
</dependency>

<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
</dependency>
<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
<!--	生成token	-->
<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt</artifactId>
			<version>0.9.1</version>
</dependency>

二、项目结构

三、实现过程

3.1数据库结构

application.yml

这里配置mysql的驱动 以及设置端口号

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/bishi?my_db_01=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    show-sql: true
    properties:
      hibernate:
        format_sql: true
server:
  port: 8183

DBUtil.class

这里将mysql的一些操作直接封装成一个实体类

package com.example.bcryptpasswordencoder.utils;

import java.sql.*;

public class DBUtil {
    static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver";
    static final String DB_URL = "jdbc:mysql://localhost:3306/my_db_01?useUnicode=true&characterEncoding=UTF-8";
    static final String USER = "root";
    static final String PASS = "root";

    static {
        try {
            Class.forName(JDBC_DRIVER);
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private Connection conn;
    private Statement stat;
    private PreparedStatement pstmt;

    public void openConnection() {
        try {
            conn = DriverManager.getConnection(DB_URL, USER, PASS);
            conn.setAutoCommit(true);
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public Statement getStatement() {
        openConnection();
        try {
            stat = conn.createStatement();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return stat;
    }
    public PreparedStatement getPreparedStatement(String sql) {
        openConnection();
        try {
            pstmt = conn.prepareStatement(sql);
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return pstmt;
    }
    public void closeResource() {
        try {
            if (pstmt != null && !pstmt.isClosed()) {
                pstmt.close();
            }

            if (stat != null && !stat.isClosed()) {
                stat.close();
            }

            if (conn != null && !conn.isClosed()) {
                conn.close();
            }

        } catch (SQLException e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }
}

3.2 实体类 Users

这里习惯注意和数据库的字段名匹配比较好,以后用到mybatis这样的操作可以避免一些错误

@Data 的使用自动生成set和get方法

package com.example.bcryptpasswordencoder.entity;

import lombok.Data;

@Data
public class Users {
    private long id;
    private String username;
    private String password;
    private String usernike;
}

3.3 Dao层

该项目主要实现三个接口,添加用户、登录、和更新操作

package com.example.bcryptpasswordencoder.dao;

import java.util.Map;

public interface UsersDao {
//    添加用户 对密码进行加密
    Map<String,Object> bcryptPassword(String username,String password);
//    登录
    Map<String,Object> login(String username,String password);
//    更新昵称
    Map<String,Object> updateUserNick(String username,String usernick);
}

3.4 controller层

注册用户模块:主要是为了实现用户注册成功后,对存入数据库的密码进行加密(但是这里我没有实现对密码用户名的限定等等,你们自己可以deng

登录模块:这里主要是实现用户登录成功之后使用jwt生成token

更新模块:主要是为了实现使用token,对token的有效判断还有token解密,最后实现用户的更新操作

package com.example.bcryptpasswordencoder.controller;

import com.example.bcryptpasswordencoder.impl.UsersImpl;
import com.example.bcryptpasswordencoder.utils.JwtUtil;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

@RequestMapping("/users")
@RestController
@CrossOrigin
public class UsersController {
    UsersImpl users = new UsersImpl();
//注册用户
    @PostMapping(value = "/bcryptPassword")
    public Map<String, Object> bcryptPassword(String username, String password) {
        Map<String,Object> map = new HashMap<>();
        map = users.bcryptPassword(username,password);
        return map;
    }
//登录
    @PostMapping(value = "/login")
    public  Map<String, Object> login(String username, String password){
        Map<String,Object> map = new HashMap<>();
        map = users.login(username,password);
        return map;
    }
//更新
    @PostMapping(value = "/updateUserNick")
    public Map<String,Object> updateUserNick(HttpServletRequest httpServletRequest, String userNick){
//        System.out.println(userNick);
        Map<String,Object> map = new HashMap<>();
//        首选判断token是否有效
        if(!JwtUtil.checkToken(httpServletRequest)){
            map.put("code",500);
            map.put("msg","token无效");
            return map;
        }
//        解密username
        String username = JwtUtil.getUserIdByJwtToken(httpServletRequest);
        map = users.updateUserNick(username,userNick);
        return map;
    }
}

3.5 impl

加密使用的是 BCryptPasswordEncoder

我这里是为了顺便练习一下jdbc,大家觉得繁琐可以直接使用mybatis.

package com.example.bcryptpasswordencoder.impl;

import com.example.bcryptpasswordencoder.dao.UsersDao;
import com.example.bcryptpasswordencoder.entity.Users;
import com.example.bcryptpasswordencoder.utils.DBUtil;
import com.example.bcryptpasswordencoder.utils.JwtUtil;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class UsersImpl implements UsersDao {
    DBUtil dbUtil = new DBUtil();
    //        创建一个BCryptPasswordEncoder对象
    BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    @Override
    public Map<String, Object> bcryptPassword(String username, String password) {
//        对密码进行加密
        String password1 = passwordEncoder.encode(password);
        Map<String,Object> map = new HashMap<>();
//        数据库操作
        dbUtil.openConnection();
        PreparedStatement ps;
//        定义一个sql语句
        String sql="insert into users(username,password) values(?,?)";
        ps = dbUtil.getPreparedStatement(sql);
        int count=0;//判断sqlzhi
        try {
            ps.setString(1,username);
            ps.setString(2,password1);
            count = ps.executeUpdate();
//            关闭数据库连接
            dbUtil.closeResource();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        if(count>0) {
            map.put("code", 200);
            map.put("count", 0);
            map.put("msg", "添加用户成功");
            map.put("data", "");
        }else{
            map.put("code", 200);
            map.put("count", 0);
            map.put("msg", "添加用户失败");
        }

        return map;
    }

    @Override
    public Map<String, Object> login(String username, String password) {
        Map<String,Object> map = new HashMap<>();
        ArrayList<Users> users = new ArrayList<>();
//        通过username查找用户
//        定义sql语句
        String sql ="select * from users where username=?";
//        数据库操作
        dbUtil.openConnection();
        PreparedStatement ps;
        ps = dbUtil.getPreparedStatement(sql);
        try {
            ps.setString(1,username);
            ResultSet rs = ps.executeQuery();
            Users user;
            while(rs.next())
            {
                user = new Users();
                user.setId(rs.getInt("id"));
                user.setUsername(rs.getString("username"));
                user.setPassword(rs.getString("password"));
                users.add(user);
            }
            dbUtil.closeResource();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        if(users.size()>0){
//            证明有该用户
//            判断密码是否正确
           boolean matches  =  passwordEncoder.matches(password,users.get(0).getPassword());
//           生成token
           String token = JwtUtil.getJwtToken(users.get(0).getId(),users.get(0).getUsername());
           if(matches){
//               匹配成功
               map.put("code", 200);
               map.put("count", users.size());
               map.put("msg", "登录成功");
               map.put("data", users);
               map.put("token",token);
           }else{
               map.put("code", 500);
               map.put("count", 0);
               map.put("msg", "登录失败");
           }
        }
        return map;
    }

    @Override
    public Map<String, Object> updateUserNick(String username, String userNick) {
        Map<String,Object> map = new HashMap<>();
        int i= 0;//判断更新是否成功
//       数据库操作
        dbUtil.openConnection();
        PreparedStatement ps;
        try {
//                对昵称进行修改
//                定义sql语句
                String strSql = "update users set nickname = ? where username=?";
                ps = dbUtil.getPreparedStatement(strSql);
                ps.setString(1,userNick);
                ps.setString(2,username);
                i= ps.executeUpdate();
            dbUtil.closeResource();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        if(i>0){
            map.put("code", 200);
            map.put("count", 0);
            map.put("msg", "更新成功");
            map.put("data", "");
        }else{
            map.put("code", 500);
            map.put("count", 0);
            map.put("msg", "更新失败");
        }
        return map;
    }
}

3.6JwtUtil

这里大家如果不理解的话可以查阅这篇文章,写得很好https://blog.csdn.net/weixin_45070175/article/details/118559272

package com.example.bcryptpasswordencoder.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

public class JwtUtil {
//    token 时效 12小时
    public static final long EXPIRE = 1000*60*60*12;
//    签名哈希的密钥,对于不同的加密算法来说含义不同
    public static final String APP_SECRET = "hss200923usersToken";

    /**
     * 根据用户id和用户名生成token
     * @param id 用户id
     * @param username 用户名称
     * @return JWT规则生成的token
     */
    public static String getJwtToken(long id,String username){
        String JwtToken = Jwts.builder()
                .setHeaderParam("typ","JWT")
                .setHeaderParam("alg","HS256")
                .setSubject("users")
                .setIssuedAt(new Date())//token 保留时间
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))//token失效时间
                .claim("id",id)
                .claim("username",username)
//                HS256算法实际上就是MD5加盐值,此时APP_SECRET就代表盐值
                .signWith(SignatureAlgorithm.HS256,APP_SECRET)
                .compact();
        return JwtToken;
    }

    /**
     * 判断token是否存在与有效
     * @param jwtToken token字符串
     * @return 如果token 有效返回true,否则返回false
     */
    public static boolean checkToken(String jwtToken){
        if(StringUtils.isEmpty(jwtToken)) return false;
        try {
            Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        }catch(Exception e){
           e.printStackTrace();
           return false;
        }
        return true;
    }

    /**
     * 判断token 是否存在与有效
     * @param request
     * @return
     */
    public static boolean checkToken(HttpServletRequest request){
        try{
//            从http请求头中获取token字符串
            String jwtToken = request.getHeader("token");
            if(StringUtils.isEmpty(jwtToken)) return false;
            Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        }catch(Exception e){
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 根据token 获取用户username
     * @param request Http 请求对象
     * @return 解析token后获得的用户id
     */
    public static String getUserIdByJwtToken(HttpServletRequest request){
        String jwtToken = request.getHeader("token");
        if(StringUtils.isEmpty(jwtToken)) return "";
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        Claims claims = claimsJws.getBody();
        return (String)claims.get("username");
    }
}

四、操作

标签:username,map,加密,SpringBoot,token,put,import,String
From: https://www.cnblogs.com/xiedy001/p/16944793.html

相关文章

  • Springboot 整合 SpringCache 使用 Redis 作为缓存
    一直以来对缓存都是一知半解,从没有正经的接触并使用一次,今天腾出时间研究一下缓存技术,开发环境为OpenJDK17与SpringBoot2.7.5源代码下载地址:https://hanzhe.lanzoue.com/i......
  • java解加密(AES/CBC)异常:java.lang.SecurityException: JCE cannot authenticate the
    原文链接:https://blog.csdn.net/weixin_43048843/article/details/109200673对接第三方厂商需求时,需要对数据AES256进行解密,由于java本身不支持,需要添加依赖。一、版本适......
  • Task记录3 :ContinueWith ,CancellationToken,的结合
    staticvoidMain(string[]args){//1.创建取消令牌数据CancellationTokenSourcetokenSource=newCancellationTokenSource();......
  • grub加密与解密
    前言grub默认无加密,用户可免密以单用户模式进入系统修改root密码。若想增强其安全性,可以将grub加密。GRUB2提供两种类型的密码保护:修改菜单条目时需要密码,但启动菜单......
  • Vue RSA加密
    1.安装jsencryptnpminstalljsencrypt2.引入jsencrypt//全局引入importJSEncryptfrom"jsencrypt";Vue.prototype.$jsEncrypt=JSEncrypt;//局部引入impor......
  • springboot 加入websocket后,ServerEndpointExporter配置不识别-解决
    1.背景springboot加入websocket,需要配置ServerEndpointExporter的bean,发现没法识别2.原因springboot内置了tomcat,内置的tomcat与websocket不兼容,因此需要将-start-w......
  • springboot配置多个数据源
    前言,什么是数据源与数据库连接池:说SpringBoot的多数据源配置之前,我们先了解下DataSource。在java中,操作数据库有很多方式,在众多方式中除了JDBC外还有DataSource对象......
  • Python加密操作 对称加密/非对称加密
    安装包: pycryptodomehttps://pycryptodome.readthedocs.io/en/latest/src/installation.html#compiling-in-linux-ubuntu 1fromCrypto.HashimportSHA2562f......
  • Springboot+freemaker+eureka+fegin实现多文件上传,完整demo
    可能一般用fegin实现文件上传的不多,但这也算是一个文件上传方式吧,如果用到了,可以考虑借鉴一下,直接上代码好了eurekapom.xml<?xmlversion="1.0"encoding="UTF-8"?><......
  • SpringBoot中如何访问静态资源
    Springboot中如何访问静态资源我们在使用SpringMVC框架时,静态资源会被拦截,所以我们需要添加额外配置过滤静态资源,让其不被拦截。那么在Springboot中怎么配置呢。一.传统SS......