Spring Security密码加密(AES)

当你自己写一个登录页面的时候,你的密码没有加密会直接暴漏出来,那么我们就需要进行对你输入的密码进行加密
下面我就演示一下用ASE加密的方式来实现

一、前端加密

前端你需要一个key和vi你可以自定义,然后发送请求的时候,把这两个参数发过去
在这里插入图片描述
在这里插入图片描述

二、后端解密(基于Spring Security)

这是ASE工具类,key和vi必须和前端一致

package com.navimentum.officialWebsite.util;

import cn.hutool.core.util.HexUtil;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Objects;

/**
 * =======================
 * Introduce:
 * User: Jiangjr
 * Date: 2022/7/8
 * ASE解密工具类
 * =======================
 */
public class EncryptUtil {
    // key:必须16个字符,且要和前端保持一致
    private final static String KEY = "0123456789ASDFGH";
    // 偏移量:必须16个字符,且要和前端保持一致
    private final static String IV = "ASDFGH0123456789";

    /**
     * 将解密返回的数据转换成 String 类型
     * @param content Base64编码的密文
     */
    public static String decrypt(String content) {
        return new String(Objects.requireNonNull(aesCbcDecrypt(parseHexStr2Byte(content), KEY.getBytes(), IV.getBytes())));
    }

    private static byte[] aesCbcEncrypt(byte[] content, byte[] keyBytes, byte[] iv) {
        try {
            SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
            //设置模式,编码,后端为PKCS5Padding,对应前端是Pkcs7
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
            return cipher.doFinal(content);
        } catch (Exception e) {
            System.out.println("exception:" + e.toString());
        }
        return null;
    }

    private static byte[] aesCbcDecrypt(byte[] content, byte[] keyBytes, byte[] iv) {
        try {
            SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
            return cipher.doFinal(content);
        } catch (Exception e) {
            System.out.println("exception:" + e.toString());
        }
        return null;
    }

    /**
     * 将16进制String转换为byte数组
     */
    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1) {
            return null;
        }
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }
}

Security是基于DaoAuthenticationProvider类进行解密所以我们只需要重写里面的方法即可

package com.navimentum.officialWebsite.config.SecuriytConfig;

import com.navimentum.officialWebsite.service.Impl.UserDetailsServiceImpl;
import com.navimentum.officialWebsite.util.EncryptUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * =======================
 * Introduce:
 * User: Jiangjr
 * Date: 2022/7/8
 * ASE解密
 * =======================
 */
public class MyAuthenticationProvider extends DaoAuthenticationProvider {

    //UserDetailsServiceImpl是你获取数据库账号和密码的接口
    public MyAuthenticationProvider(UserDetailsServiceImpl userDetailsService) {
        setUserDetailsService(userDetailsService);
    }

    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        if (authentication.getCredentials() == null) {
            this.logger.debug("Authentication failed: no credentials provided");
            throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
        } else {
            String presentedPassword = authentication.getCredentials().toString();
            System.out.println("加密前密码"+presentedPassword );

            // 对登录密码进行解密
            presentedPassword = EncryptUtil.decrypt(presentedPassword);
            System.out.println("解密后密码"+presentedPassword );
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {//前面是明文,后面是编码,判断是否一致
                this.logger.debug("Authentication failed: password does not match stored value");
                throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
            }
        }
    }
}

这是我自己定义的UserDetailsServiceImpl要实现Security中的UserDetailsService,然后我自己建的mapper去查询数据库的用户和密码

package com.navimentum.officialWebsite.service.Impl;

import com.navimentum.officialWebsite.mapper.SysUserMapper;
import com.navimentum.officialWebsite.model.SysUser;
import com.navimentum.officialWebsite.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * =======================
 * Introduce:
 * User: Jiangjr
 * Date: 2022/6/22
 * =======================
 */
@Service(value = "userDetailsService")
@Transactional
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private SysUserMapper sysUserMapper;


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if (StringUtils.isEmpty(username)){
            throw new RuntimeException("用户名不可为空");
        }

        //用户不为空,查询用户信息
        SysUser sysUser = sysUserMapper.selectSysUserByUsername(username);
        if (sysUser == null){
            throw new UsernameNotFoundException(String.format("{}用户不存在",username));
        }

        //用户存在,返回用户信息
        List<GrantedAuthority> grantedAuthorityList = new ArrayList<>();
        //根据用户获取角色,获取权限集合
        List<String> codeList = sysUserMapper.selectRoleCodeByUsername(username);
        codeList.forEach(code->{
            SimpleGrantedAuthority authority = new SimpleGrantedAuthority(code);
            grantedAuthorityList.add(authority);
        });
        return new User(sysUser.getUsername(),sysUser.getPassword(),grantedAuthorityList);
    }
}

最后在SecurityConfig类里进行配置就OK了(SecurityConfig类是你自己写的关于Security的一些配置)

package com.navimentum.officialWebsite.config.SecuriytConfig;//package com.navimentum.officialWebsite.config.SecuriytConfig;

import com.navimentum.officialWebsite.service.Impl.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * =======================
 * Introduce:
 * User: Jiangjr
 * Date: 2022/6/22
 * =======================
 */
//@EnableWebSecurity //实现方法级别的安全配置 开启注解
//@EnableGlobalMethodSecurity(prePostEnabled = true)   //实现方法级别的安全配置 开启注解
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    };

    @Lazy
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private UserDetailsServiceImpl userDetailsServiceImpl;

    /**
     * 登录成功的处理
     */
    @Autowired
    private SuccessHandler successHandler;

    /**
     * 登录失败的处理
     */
    @Autowired
    private FailHandler failHandler;

    /**
     * 未登录的处理
     */
    @Autowired
    private MyAuthenticationEntryPoint myAuthenticationEntryPoint;

    /**
     * 未授权处理
     */
    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;

    /**
     * 注销处理器
     */
    @Autowired
    private MyLogoutHandler myLogoutHandler;

    /**
     * 注销成功
     */
    @Autowired
    private MyLogoutSuccessHandler myLogoutSuccessHandler;

    /**
     * 超时管理
     */
    @Autowired
    private MyInvalidSessionStrategy myInvalidSessionStrategy;

    /**
     * 被挤下线处理
     */
    @Autowired
    private MySessionInformationExpiredStrategy mySessionInformationExpiredStrategy;



    /**
     * 授权
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll() // 放行/login的请求,但是用户密码必须正确
                .antMatchers("/api") //访问/api需要什么权限和什么角色  可以注解实现 @PreAuthorize("hasAnyRole('panshAdmin')") or @PreAuthorize("hasAnyAuthority('ROLE_admin')")
                .hasAnyAuthority("ROLE_admin")
//                .antMatchers("/api/**")
//                .hasAnyRole("panshAdmin")
//                .anyRequest() //拦截所有请求
//                .authenticated()
                .and()
                .logout().permitAll() //允许注销
                .addLogoutHandler(myLogoutHandler)
                .logoutSuccessHandler(myLogoutSuccessHandler)
                .deleteCookies("JSESSIONID") //登出之后删除Cookie
                .and()
                .formLogin()
                .loginProcessingUrl("/login")
                .successHandler(successHandler) //登录成功返回消息
                .failureHandler(failHandler) //登录失败返回消息
                .and()
                .exceptionHandling()
//                .accessDeniedHandler(myAccessDeniedHandler)//权限不足处理
                .authenticationEntryPoint(myAuthenticationEntryPoint)//未登录的处理
                .and()
                .authenticationProvider(new MyAuthenticationProvider(userDetailsServiceImpl));//接受前端加密的密码进行解码(ASE)
//                .and()
//                .sessionManagement()
//                .invalidSessionStrategy(myInvalidSessionStrategy) //超时管理
//                .sessionCreationPolicy(SessionCreationPolicy.STATELESS) //无状态的,任何状态下都不会生成session
//                .maximumSessions(1) //最大可同时几个人登录
//                .maxSessionsPreventsLogin(false) //是否允许登录
//                .expiredSessionStrategy(mySessionInformationExpiredStrategy);//挤号处理


        //关闭CSRF一般指跨站请求伪造
        http.csrf().disable();
    }

    /**
     * 认证
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
    }
}

主要是这里
在这里插入图片描述
以下是我数据库的关于Security的表和结构

在这里插入图片描述

sys_role表

![在这里插入图片描述](https://img-blog.csdnimg.cn/805db4bd53344de39dd7ef191afca799.png

sys_user表

在这里插入图片描述
sys_user_role表

在这里插入图片描述
如果你们只是需要登录,而不需要根据角色显示某个模块,就只需要sys_user表就可以实现。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱穿背带裤的馫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值