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

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

一、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");
    }
}

四、操作

 

 

 

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值