登陆信息的加密和获取权限访问

实现用户密码的加密的操作:用户注册时,根据传过来的信息,在数据库中查询是否存在这个用户,如果不存在就给它的密码进行加密,加密后的信息存储到数据库中,当登陆时对登陆密码再进行加密,与数据库中的加密信息进行校验

如果只想要知道信息加密,有关过滤器,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>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot中整合Spring Security可以实现登录认证和数据权限管理。下面是简单的步骤: 1. 添加依赖 在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> ``` 2. 配置Spring Security 在主配置类中添加@EnableWebSecurity注解,开启Spring Security,并且创建一个继承自WebSecurityConfigurerAdapter的配置类,用于配置Spring Security。 ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { // 配置登录页面和登录请求的路径 http.formLogin() .loginPage("/login") .loginProcessingUrl("/login") .defaultSuccessURL("/home") .and() // 配置退出登录的路径和跳转页面 .logout() .logoutUrl("/logout") .logoutSuccessUrl("/login") .and() // 配置拦截规则 .authorizeRequests() .antMatchers("/login").permitAll() .anyRequest().authenticated() .and() // 关闭CSRF保护 .csrf().disable(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 配置用户信息和密码加密方式 auth.inMemoryAuthentication() .passwordEncoder(new BCryptPasswordEncoder()) .withUser("admin") .password(new BCryptPasswordEncoder().encode("admin")) .roles("ADMIN"); } } ``` 3. 配置数据权限管理 如果需要实现数据权限管理,可以在配置类中添加一个实现了FilterInvocationSecurityMetadataSource接口的类,用于获取当前请求所需的权限信息,并且在配置类中添加一个实现了AccessDecisionManager接口的类,用于判断当前用户是否有访问该资源的权限。 ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomFilterInvocationSecurityMetadataSource customFilterInvocationSecurityMetadataSource; @Autowired private CustomAccessDecisionManager customAccessDecisionManager; @Override protected void configure(HttpSecurity http) throws Exception { // 配置拦截规则 http.authorizeRequests() .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() { @Override public <O extends FilterSecurityInterceptor> O postProcess(O object) { object.setSecurityMetadataSource(customFilterInvocationSecurityMetadataSource); object.setAccessDecisionManager(customAccessDecisionManager); return object; } }) .and() // 关闭CSRF保护 .csrf().disable(); } } ``` 参考资料: 1. Spring Security官方文档:https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/ 2. Spring Boot整合Spring Security实现登录认证和数据权限管理:https://www.jianshu.com/p/04d848c9cb8d

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值