实现用户密码的加密的操作:用户注册时,根据传过来的信息,在数据库中查询是否存在这个用户,如果不存在就给它的密码进行加密,加密后的信息存储到数据库中,当登陆时对登陆密码再进行加密,与数据库中的加密信息进行校验
如果只想要知道信息加密,有关过滤器,token生成的相关工具类相关操作可以略过。。。。。。。
项目结构:
用户实体类:
没有显示对应的getter和setter方法!!!
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serializable;
import java.time.LocalDateTime;
public class User implements Serializable {
private static final long serialVersionUID=1L;
//主键编号
private Long id;
/*用户名*/
private String username;
/*密码*/
private String password;
/*昵称*/
private String nickname;
/*性别*/
private Integer sex;
/*姓名*/
private String name;
/*创建时间*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
controller层:
两个方法登陆和注册,登陆还涉及到了token的生成,这个token在下面有说明
package com.example.demo.controller;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import com.example.demo.utils.Result;
import com.example.demo.utils.ZbLpFileUtils;
import com.mysql.cj.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userservice;
/**
* 注册
* */
@ResponseBody
@PostMapping("/register")
public Map register(@RequestBody User user){
//判断参数是否为空
if (StringUtils.isNullOrEmpty(user.getUsername())) return Result.errorInput("用户名为空");
if (StringUtils.isNullOrEmpty(user.getPassword())) return Result.errorInput("密码为空");
return userservice.register(user);
}
/**
* 登陆
* */
@ResponseBody
@PostMapping("/login")
public Map login(@RequestBody User user, HttpServletRequest request){
//判断参数
if (StringUtils.isNullOrEmpty(user.getUsername())) return Result.errorInput("用户名");
if (StringUtils.isNullOrEmpty(user.getPassword())) return Result.errorInput("密码");
return userservice.login(user,request.getSession());
}
}
service层:
import com.example.demo.entity.User;
import javax.servlet.http.HttpSession;
import java.util.List;
import java.util.Map;
public interface UserService {
/**
* 注册
* */
Map register(User user);
/**
* 登陆
* */
Map login(User user, HttpSession session);
}
imp层:
这一层主要就是从数据库中取出数据,取出的数据与传进来的值进行校验,另外这里有一个工具类,主要是负责密码的加密,这个工具类是Md5Utils
Md5Utils类:
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Md5Utils {
/**
* MD5加密
* */
public static String md5(String str){
try {
//生成一个Md5加密计算,MessageDigest.getInstance(),可以选择其他的加密方式
MessageDigest md5 = MessageDigest.getInstance("MD5");
//计算MD5函数,参数:转换成字节的要加密的String
md5.update(str.getBytes());
//是个字节类型数组,总之打印出来是一堆看不懂的玩意儿
byte[] digest = md5.digest();
//生成了一个加密后的String类型的信息,将BigInteger的符号大小表示法转换成一个BigInteger值
//BigInteger(int signum, byte[] magnitude):
return new BigInteger(1,md5.digest()).toString(16);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
}
登陆操作的讲解:在登陆中的操作中,会有一个生成token的操作,在登陆的时候为什么要有token的生成呢?在一个网站中,可以设置访问权限,除了登陆和注册的功能可以设置不用token登陆(设置了访问权限,你怎么登陆呢?),其余的功能就必须要有token这个东西进行访问,不然的别人可以任意访问你的个人信息。这个token就好像一把钥匙,没有这个钥匙,你就没办法打开对应的锁,相对的也就没办法访问对应的Controller资源咯!!!
token是存放在请求头中的,需要使用测试接口设置
不允许随意访问controller,需要设置过滤器,另外这是一个后端,不涉及前端,所以要实现访问过滤的情况,需要使用测试接口,这个测试接口就不在这里说明了。
过滤器代码:
import com.alibaba.fastjson.JSON;
import com.example.demo.utils.LpJwTokenUtils;
import com.example.demo.utils.Result;
import com.github.isrsal.logging.RequestWrapper;
import com.github.isrsal.logging.ResponseWrapper;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 过滤器
* */
@Component
public class LpFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
ResponseWrapper responseWrapper = new ResponseWrapper(Thread.currentThread().getId(), response);
RequestWrapper requestWrapper = new RequestWrapper(Thread.currentThread().getId(), request);
requestWrapper.setCharacterEncoding("UTF-8");
HttpSession session = request.getSession();
//设置允许跨域的配置
// 这里填写你允许进行跨域的主机ip(正式上线时可以动态配置具体允许的域名和IP)
responseWrapper.setHeader("Access-Control-Allow-Origin", "*");
// 允许的访问方法
responseWrapper.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE,PUT");
// Access-Control-Max-Age 用于 CORS 相关配置的缓存
responseWrapper.setHeader("Access-Control-Max-Age", "3600");
//允许请求方在header中携带的信息
responseWrapper.setHeader("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization");
//设置编码格式
responseWrapper.setCharacterEncoding("UTF-8");
responseWrapper.setContentType("application/json; charset=utf-8");
//得到uri地址 - 接口地址
String requestURI = requestWrapper.getRequestURI();
//判断可以过滤的地址
if(isUri(requestURI)){
//允许请求访问到controller
chain.doFilter(requestWrapper,responseWrapper);
}else{
//返回map
Map<String,Object> result=null;
boolean isFilter=false;
//获得token
String token=requestWrapper.getHeader("Authorization");
//校验token是否有效
if(token==null ||token.trim().isEmpty()){
result= Result.errorToken("token不存在");
}else if(!token.equals(session.getAttribute(LpJwTokenUtils.getTokenSubject(token)))){
result=Result.errorToken("token无效");
}else if(LpJwTokenUtils.isExpiration(token)){
result=Result.errorInput("token过期");
}else{
isFilter=true;
}
//通过
if (isFilter){
chain.doFilter(requestWrapper,responseWrapper);
}else{
//返回错误
PrintWriter writer =null;
OutputStreamWriter osw=null;
try {
//创建一个输出流 设置编码格式
osw=new OutputStreamWriter(response.getOutputStream(),"UTF-8");
//创建字符打印流对象
writer=new PrintWriter(response.getOutputStream(),true);
//转换成json字符传 输出
writer.write(JSON.toJSONString(result));
}finally {
if (writer!=null) writer.close();
if (osw!=null) osw.close();
}
}
}
}
/**
* 是可以通过的接口
* */
private boolean isUri(String requestUri){
List<String> list=new ArrayList<>();
list.add("user/register");//注册
list.add("user/login");//登陆
for (String s : list) {
if (requestUri.indexOf(s)>-1) return true;
}
return false;
}
@Override
public void destroy() {
}
}
在这里生成token的需要的参数是:用户的id,用户的用户名和密码,因此写了一个LpTokenLogin类用于存放这三个参数,
LpTokenLogin类:
public class LpTokenLogin {
private static final long serialVersionUId=1L;
/*主键编号*/
private Long id;
/*用户名*/
private String username;
/*密码*/
private String password;
/*token,生成token后,用于存放*/
private String token;
public LpTokenLogin() {
}
public LpTokenLogin(Long id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
生成token的工具类:这个类里面有四个属性,参与了token的生成,里面包含了五个有关token方法,token的创建,得到token的内容,判断token是否过期,生成主题(这个没什么用,就是在把token存到session中,给一个键值),得到主题
LpJwToken类:
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class LpJwTokenUtils {
//这些属性的内容都可以自己定义
//密钥用于解密
private static final String PRIMARY_KEY="key_zbxxxx";
//签发者
private static final String ISS="Gent.Ni";
//添加角色的key
private static final String TOKEN_INFO="tokenInfo";
//过期时间是3600秒*24小时
public static final Long EXPIRATION=3600L*24;
/**
* 创建token
* 字符串
* 实体对象
* */
public static String createToken(String str,Object object){
Map<String,Object> map=new HashMap<>();
map.put(TOKEN_INFO,object);
JwtBuilder builder = Jwts.builder()
//采用HS512算法对JWT进行的签名,PRIMARY_KEY 是我们的密钥
.signWith(SignatureAlgorithm.HS512, PRIMARY_KEY)
//设置内容
.setClaims(map)
//设置发证人
.setIssuer(ISS)
//设置主题
.setSubject(str)
//设置发布时间
.setIssuedAt(new Date())
//设置时间有效期
.setExpiration(new Date(System.currentTimeMillis()+EXPIRATION*1000));
return builder.compact();
}
/**
* 判断token是否过期
* */
public static boolean isExpiration(String token){
//判断 token日期 小于 当前日期 返回 true (已过期)
return getTokenBody(token).getExpiration().before(new Date());
}
/**
* 得到主题
* */
public static String getTokenSubject(String token){
return getTokenBody(token).getSubject();
}
/**
* 主题 唯一
* */
public static String getSubjectName(String name){
return "token_subject_"+name;
}
/**
* 得到token的内容
* */
public static Claims getTokenBody(String token){
return Jwts.parser().setSigningKey(PRIMARY_KEY).parseClaimsJws(token).getBody();
}
}
UserServiceImpl实现类:
import com.example.demo.entity.LpTokenLogin;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
import com.example.demo.utils.LpJwTokenUtils;
import com.example.demo.utils.Md5Utils;
import com.example.demo.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpSession;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public Map register(User user) {
//查询用户名,不能重复
User userName = userMapper.getUserName(user.getUsername());
if (userName!=null) return Result.errorInput("该用户名已经被注册");
//密码加密
user.setPassword(Md5Utils.md5(user.getPassword()));
//创建时间
user.setCreateTime(LocalDateTime.now());
//新增
int insert = userMapper.insert(user);
if (insert>0){
return Result.success(user);
}else
return Result.error();
}
@Override
public Map login(User user, HttpSession session) {
//根据用户名进行查询
User u = userMapper.getUserName(user.getUsername());
//判断密码是否正确
if (u==null||u.getPassword().equals(Md5Utils.md5(user.getPassword())))
return Result.error("用户名不存在或者密码错误");
//返回一个对象用于存储用户的id,用户名,密码,没有则创建这个类
LpTokenLogin lpTokenLogin = new LpTokenLogin(u.getId(), u.getUsername(), u.getPassword());
//主题
String subjectName = LpJwTokenUtils.getSubjectName(lpTokenLogin.getId().toString());
//生成token
String token = LpJwTokenUtils.createToken(subjectName, lpTokenLogin);
//存储
session.setAttribute(subjectName,token);
lpTokenLogin.setToken(token);
return Result.success(lpTokenLogin);
}
}
这里写了一个Result类:用于返回数据
import java.util.HashMap;
import java.util.Map;
/**
* 返回
**/
public class Result {
public static Map<String,Object> errorToken(String msg) {return result(999,msg,null);}
public static Map<String,Object> errorInput(String msg){
return error("请输入" + msg);
}
public static Map<String,Object> success(){
return result(200,"成功",null);
}
public static Map<String,Object> success(Object o){
return result(200,"成功",o);
}
public static Map<String,Object> error(){
return result(500,"失败",null);
}
public static Map<String,Object> error(String msg){
return result(500,msg,null);
}
public static Map<String,Object> result(int code,String msg,Object o){
Map<String,Object> map = new HashMap<>();
map.put("code",code);
map.put("msg",msg);
map.put("data",o);
return map;
}
}
有关数据库语句的操作:
UserMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
<resultMap id="UserResult" type="com.example.demo.entity.User">
<result property="id" column="id"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
<result property="nickname" column="nickname"/>
<result property="sex" column="sex"/>
<result property="name" column="name"/>
<result property="createTime" column="create_time"/>
</resultMap>
<sql id="userSql">
select id,username,password,nickname,sex,name,create_time from user
</sql>
<select id="listUser" resultMap="UserResult">
<include refid="userSql"/>
</select>
<select id="getUserName" resultMap="UserResult" parameterType="String">
<include refid="userSql"/>
where
username=#{username}
</select>
<insert id="insert" parameterType="com.example.demo.entity.User" useGeneratedKeys="true" keyProperty="id">
insert into user
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="username !=null and username !=''">username,</if>
<if test="password !=null and password !=''">password,</if>
<if test="nickname !=null and nickname !=''">nickname,</if>
<if test="sex !=null and sex !=''">sex,</if>
<if test="name !=null and name !=''">name,</if>
<if test="createTime !=null and createTime !=''">create_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="username !=null and username !=''">#{username},</if>
<if test="password !=null and password !=''">#{password},</if>
<if test="nickname !=null and nickname !=''">#{nickname},</if>
<if test="sex !=null and sex !=''">#{sex},</if>
<if test="name !=null and name !=''">#{name},</if>
<if test="createTime !=null and createTime !=''">#{createTime},</if>
</trim>
</insert>
</mapper>
数据库语句:
CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键id',
`username` varchar(50) DEFAULT NULL COMMENT '用户名',
`password` varchar(50) DEFAULT NULL COMMENT '密码',
`nickname` varchar(50) DEFAULT NULL COMMENT '昵称',
`sex` tinyint(1) DEFAULT NULL COMMENT '性别(0:女 1:男)',
`name` varchar(50) DEFAULT NULL COMMENT '姓名',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8mb3 COMMENT='用户表';
/*Data for the table `user` */
insert into `user`(`id`,`username`,`password`,`nickname`,`sex`,`name`,`create_time`) values (4,'罗宾','111111','考古家',1,'腹黑','2021-09-02 11:41:38'),(5,'乌索普','222222','射手',1,'骗子','2021-09-02 11:41:38'),(6,'索隆','000000','剑豪',1,'绿头','2021-09-09 16:10:02'),(7,'路飞','666666','海贼王',1,'二货','2021-09-10 10:48:05');
对应的application.yml配置:
server:
port: 8081
tomcat:
uri-encoding: UTF-8
spring:
datasource:
url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai
username: root
password: xxxxx
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:mapper/*Mapper.xml
type-aliases-package: com.example.test.entity
对应的pom依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!--<scope>runtime</scope>-->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--spring扩展-->
<dependency>
<groupId>com.github.isrsal</groupId>
<artifactId>spring-mvc-logger</artifactId>
<version>0.2</version>
</dependency>
<!--JWT-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<!--JSON-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.50</version>
</dependency>