作者 朱兆平

add:

用户登录认证采用SM3加密方式.
新增用户与更新用户接口还没改为SM3方式
... ... @@ -10,7 +10,7 @@
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.tianbo</groupId>
<artifactId>warehouse</artifactId>
<artifactId>cloud-user-center</artifactId>
<version>5.0Beta-DataPermission</version>
<name>usercenter</name>
<description>usercenter for springcloud</description>
... ... @@ -21,6 +21,8 @@
<fastjson_version>1.2.28</fastjson_version>
<lombok_sersion>1.18.6</lombok_sersion>
<swagger2_version>2.9.2</swagger2_version>
<shiro.version>1.2.5</shiro.version>
<commons-lang3.version>3.3.2</commons-lang3.version>
</properties>
<dependencies>
... ... @@ -220,6 +222,26 @@
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 兼容卡口登录插件需要用shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<!-- 验证码配置-->
<dependency>
<groupId>com.github.axet</groupId>
<artifactId>kaptcha</artifactId>
<version>0.0.9</version>
</dependency>
</dependencies>
<dependencyManagement>
... ...
package com.tianbo.warehouse.bean;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
@Configuration
public class KaptchaConfig {
/*声明验证码生成策略属性 Bean*/
@Bean
public DefaultKaptcha captchaProducer(){
DefaultKaptcha captchaProducer =new DefaultKaptcha();
Properties properties =new Properties();
properties.setProperty("kaptcha.border","yes");
properties.setProperty("kaptcha.border.color","105,179,90");
properties.setProperty("kaptcha.textproducer.font.color","red");
properties.setProperty("kaptcha.image.width","125");
properties.setProperty("kaptcha.image.height","60");
properties.setProperty("kaptcha.textproducer.font.size","36");
properties.setProperty("kaptcha.session.key","code");
properties.setProperty("kaptcha.textproducer.char.length","4");
properties.setProperty("kaptcha.textproducer.font.names","宋体,楷体,微软雅黑");
Config config=new Config(properties);
captchaProducer.setConfig(config);
return captchaProducer;
}
}
... ...
package com.tianbo.warehouse.controller;
import com.alibaba.fastjson.JSON;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.thoughtworks.xstream.core.util.Base64Encoder;
import com.tianbo.warehouse.controller.response.ResultJson;
import com.tianbo.warehouse.model.ROLE;
import com.tianbo.warehouse.service.RoleService;
import com.tianbo.warehouse.util.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;
@Slf4j
@RestController()
@RequestMapping("/anonymous")
public class AnonymousController {
@Autowired
RoleService roleService;
@Autowired
RedisUtils redisUtils;
@Autowired
private DefaultKaptcha captchaProducer;
/**
* 配置匿名者可以访问的路由,并更新到redis,匿名者默认可以访问的role_name =ROLE_anonymous
* 此方法会将所有符合权限组名=ROLE_anonymous的权限更新到redis中,供gateway调用判断权限
* @return
*/
@PostMapping("initAnonymousRoute")
public ResultJson initAnonymousRoute(){
List<ROLE> list = roleService.getROLE_anonymousPermList();
String json = JSON.toJSONString(list);
boolean result= redisUtils.set("ROLE_anonymous_routers", json,0);
return result ? new ResultJson("200","匿名者权限配置成功") :new ResultJson("500","匿名者权限配置失败");
}
/**
* 生成验证码
*/
@RequestMapping(value = "/randCode")
public ResultJson getRandCode(){
// 生成自定义验证码文字
Random random = new Random();
int num1 = random.nextInt(100);
int num2 = random.nextInt(100);
int sum = num1 + num2;
System.out.println("验证码答案为: = " + sum);
String capText = num1 + " + " + num2 + " = ";
// 获取验证码上的文字
// String capText = captchaProducer.createText();
// 将文件渲染到图片上
BufferedImage bi = captchaProducer.createImage(capText);
ByteArrayOutputStream outputStream = null;
outputStream = new ByteArrayOutputStream();
Base64Encoder encoder = new Base64Encoder();
Map<String,Object> map = new HashMap<>();
String verifyToken = "";
try {
verifyToken = UUID.randomUUID().toString();
redisUtils.set("verifyToken:" + verifyToken,String.valueOf(sum),1200);
ImageIO.write(bi, "jpeg", outputStream);
map.put("verifyImg","data:image/jpeg;base64,"+encoder.encode(outputStream.toByteArray()));
} catch (IOException e) {
e.printStackTrace();
return new ResultJson("500","verify get error");
}
return new ResultJson("200","verify get ok",map,verifyToken);
}
}
... ...
... ... @@ -40,4 +40,11 @@ public class ResultJson<T> implements Serializable{
this.msg = msg;
this.data = data;
}
public ResultJson(String code, String msg, T data,String jwtToken) {
this.code = code;
this.msg = msg;
this.data = data;
this.jwtToken = jwtToken;
}
}
... ...
package com.tianbo.warehouse.security.config;
import com.tianbo.warehouse.security.login.SM3EncryptUtil;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@Service(value = "sm3EncodeService")
public class SM3PasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence charSequence) {
String enncodePassword = SM3EncryptUtil.passwordSm3(charSequence.toString());
return enncodePassword;
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
//用户输入的登录密码
String endcodeInputPass = SM3EncryptUtil.passwordSm3(rawPassword.toString());
return encodedPassword.equals(endcodeInputPass);
}
}
... ...
package com.tianbo.warehouse.security.config;
import com.netflix.discovery.converters.Auto;
import com.tianbo.warehouse.security.CustomUserDetailService;
import com.tianbo.warehouse.security.filter.JwtAuthenticationTokenFilter;
import com.tianbo.warehouse.security.handel.*;
import com.tianbo.warehouse.security.MyFilterSecurityInterceptor;
import com.tianbo.warehouse.security.login.MyLoginAuthenticationProcessFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
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.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsUtils;
... ... @@ -34,7 +30,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private MyFilterSecurityInterceptor myFilterSecurityInterceptor;
@Autowired
private PasswordEncoder passwordEncoder;
private PasswordEncoderImp passwordEncoder;
@Autowired
private MyAuthenticationSuccessHandler successHandler;
... ... @@ -58,6 +54,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
private final MyLoginAuthenticationProcessFilter adminAuthenticationProcessingFilter;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//user Details Service验证
... ... @@ -66,6 +64,16 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
auth.eraseCredentials(false);
}
/**
* 用户密码校验过滤器
*/
public WebSecurityConfig(MyLoginAuthenticationProcessFilter adminAuthenticationProcessingFilter) {
this.adminAuthenticationProcessingFilter = adminAuthenticationProcessingFilter;
}
/**
* 在configure(HttpSecurity http)方法中,
* 通过withObjectPostProcessor将刚刚创建的UrlFilterInvocationSecurityMetadataSource和UrlAccessDecisionManager注入进来。
... ... @@ -82,7 +90,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//跨域配置
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
//管理页面只允许管理员角色访问
.antMatchers("/admin/**","/ROLE/**","/user/**").authenticated()
.antMatchers("/admin/**","/ROLE/**","/user/**","/perm/**","/role/**").authenticated()
//任何请求,登录后可以访问
//其余的不需要验证
.anyRequest().permitAll()
... ... @@ -130,6 +138,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//关闭session
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// 自定义过滤器认证用户名密码
http.addFilterAt(adminAuthenticationProcessingFilter, UsernamePasswordAuthenticationFilter.class);
//session管理
//session失效后跳转
... ...
package com.tianbo.warehouse.security.login;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import java.io.UnsupportedEncodingException;
/**
* 封装各种格式的编码解码工具类.
* 1.Commons-Codec的 hex/base64 编码
* 2.自制的base62 编码
* 3.Commons-Lang的xml/html escape
* 4.JDK提供的URLEncoder
* @author calvin
* @version 2013-01-15
*/
public class Encodes {
private static final String DEFAULT_URL_ENCODING = "UTF-8";
private static final char[] BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
/**
* Hex编码.
*/
public static String encodeHex(byte[] input) {
return new String(Hex.encodeHex(input));
}
/**
* Hex解码.
*/
public static byte[] decodeHex(String input) {
try {
return Hex.decodeHex(input.toCharArray());
} catch (DecoderException e) {
throw Exceptions.unchecked(e);
}
}
/**
* Base64编码.
*/
public static String encodeBase64(byte[] input) {
return new String(Base64.encodeBase64(input));
}
/**
* Base64编码.
*/
public static String encodeBase64(String input) {
try {
return new String(Base64.encodeBase64(input.getBytes(DEFAULT_URL_ENCODING)));
} catch (UnsupportedEncodingException e) {
return "";
}
}
// /**
// * Base64编码, URL安全(将Base64中的URL非法字符'+'和'/'转为'-'和'_', 见RFC3548).
// */
// public static String encodeUrlSafeBase64(byte[] input) {
// return Base64.encodeBase64URLSafe(input);
// }
/**
* Base64解码.
*/
public static byte[] decodeBase64(String input) {
return Base64.decodeBase64(input.getBytes());
}
/**
* Base64解码.
*/
public static String decodeBase64String(String input) {
try {
return new String(Base64.decodeBase64(input.getBytes()), DEFAULT_URL_ENCODING);
} catch (UnsupportedEncodingException e) {
return "";
}
}
/**
* Base62编码。
*/
public static String encodeBase62(byte[] input) {
char[] chars = new char[input.length];
for (int i = 0; i < input.length; i++) {
chars[i] = BASE62[((input[i] & 0xFF) % BASE62.length)];
}
return new String(chars);
}
}
... ...
package com.tianbo.warehouse.security.login;
import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* 关于异常的工具类.
* @author calvin
* @version 2013-01-15
*/
public class Exceptions {
/**
* 将CheckedException转换为UncheckedException.
*/
public static RuntimeException unchecked(Exception e) {
if (e instanceof RuntimeException) {
return (RuntimeException) e;
} else {
return new RuntimeException(e);
}
}
/**
* 将ErrorStack转化为String.
*/
public static String getStackTraceAsString(Throwable e) {
if (e == null){
return "";
}
StringWriter stringWriter = new StringWriter();
e.printStackTrace(new PrintWriter(stringWriter));
return stringWriter.toString();
}
/**
* 判断异常是否由某些底层的异常引起.
*/
public static boolean isCausedBy(Exception ex, Class<? extends Exception>... causeExceptionClasses) {
Throwable cause = ex.getCause();
while (cause != null) {
for (Class<? extends Exception> causeClass : causeExceptionClasses) {
if (causeClass.isInstance(cause)) {
return true;
}
}
cause = cause.getCause();
}
return false;
}
/**
* 在request中获取异常类
* @param request
* @return
*/
public static Throwable getThrowable(HttpServletRequest request){
Throwable ex = null;
if (request.getAttribute("exception") != null) {
ex = (Throwable) request.getAttribute("exception");
} else if (request.getAttribute("javax.servlet.error.exception") != null) {
ex = (Throwable) request.getAttribute("javax.servlet.error.exception");
}
return ex;
}
}
... ...
package com.tianbo.warehouse.security.login;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderNotFoundException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import java.util.Objects;
/**
* 自定义认证管理器
*/
@Component
public class MyAuthenticationManager implements AuthenticationManager {
private final MyLoginAuthenticationProvider adminAuthenticationProvider;
public MyAuthenticationManager(MyLoginAuthenticationProvider adminAuthenticationProvider) {
this.adminAuthenticationProvider = adminAuthenticationProvider;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Authentication result = adminAuthenticationProvider.authenticate(authentication);
if (Objects.nonNull(result)) {
return result;
}
throw new ProviderNotFoundException("Authentication failed!");
}
}
... ...
package com.tianbo.warehouse.security.login;
import com.tianbo.warehouse.security.handel.MyAuthenticationFailHandler;
import com.tianbo.warehouse.security.handel.MyAuthenticationSuccessHandler;
import com.tianbo.warehouse.util.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 用户登录自定义校验过滤器
*/
@Slf4j
@Component
public class MyLoginAuthenticationProcessFilter extends AbstractAuthenticationProcessingFilter {
@Autowired
private RedisUtils redisUtils;
/**
* @param authenticationManager: 认证管理器
* @param adminAuthenticationSuccessHandler: 认证成功处理
* @param adminAuthenticationFailureHandler: 认证失败处理
*/
public MyLoginAuthenticationProcessFilter(MyAuthenticationManager authenticationManager, MyAuthenticationSuccessHandler adminAuthenticationSuccessHandler, MyAuthenticationFailHandler adminAuthenticationFailureHandler) {
super(new AntPathRequestMatcher("/login", "POST"));
this.setAuthenticationManager(authenticationManager);
this.setAuthenticationSuccessHandler(adminAuthenticationSuccessHandler);
this.setAuthenticationFailureHandler(adminAuthenticationFailureHandler);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (request.getContentType() == null || !request.getContentType().contains("application/x-www-form-urlencoded")) {
throw new AuthenticationServiceException("请求头类型不支持: " + request.getContentType());
}
UsernamePasswordAuthenticationToken authRequest;
try {
String loginUserName = request.getParameter("username");
String loginUserPass = request.getParameter("password");
String loginVerify = request.getParameter("verify");
String verifyToken = request.getParameter("verifyToken");
//验证码判断
String verify = "";
verify = redisUtils.get("verifyToken:" + verifyToken);
if(verify != null && loginVerify != null && verify.equals(loginVerify)){
authRequest = new UsernamePasswordAuthenticationToken(loginUserName,loginUserPass, null);
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}else {
System.out.println("验证码错误!");
throw new BadCredentialsException("验证码错误!");
}
} catch (BadCredentialsException e){
throw new PreAuthenticatedCredentialsNotFoundException(e.getMessage());
}catch (Exception e) {
throw new AuthenticationServiceException(e.getMessage());
}
return this.getAuthenticationManager().authenticate(authRequest);
}
}
... ...
package com.tianbo.warehouse.security.login;
import com.tianbo.warehouse.dao.USERSMapper;
import com.tianbo.warehouse.model.USERS;
import com.tianbo.warehouse.security.CustomUserDetailService;
import com.tianbo.warehouse.security.config.SM3PasswordEncoder;
import com.tianbo.warehouse.util.RedisUtils;
import org.apache.shiro.codec.CodecException;
import org.apache.shiro.crypto.hash.Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Arrays;
import org.apache.shiro.codec.CodecSupport;
/**
* 自定义认证处理类
*/
@Component
public class MyLoginAuthenticationProvider extends CodecSupport implements AuthenticationProvider {
@Autowired
private CustomUserDetailService userDetailsService;
@Resource
private USERSMapper userMapper;
@Autowired
private RedisUtils redisUtils;
@Autowired
SM3PasswordEncoder sm3PasswordEncoder;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 获取前端表单中输入后返回的用户名、密码
String userName = (String) authentication.getPrincipal();
String password = (String) authentication.getCredentials();
USERS userInfo = (USERS) userDetailsService.loadUserByUsername(userName);
//验证登录密码是否符合规则,如位数包含的字符等
boolean isValid = true;
// 验证密码
if (!isValid) {
//todo: 登录次数超了 锁定账户
throw new BadCredentialsException("密码错误!");
}
if(!userInfo.isEnabled()){
throw new DisabledException("用户被禁用");
}
/**
* ----------------
*/
//取盐规则
byte[] salt = PasswordSaltUtils.getSalt16(userInfo.getPassword());
//真实密码
String realPass = PasswordSaltUtils.getPassword16(userInfo.getPassword());
//用户登录密码与盐运算
Object tokenHashedCredentials = this.hashProvidedCredentials(password,salt,1024);
/**
* ----------------
*/
try{
String loginUserLock = redisUtils.get("user:lock:"+userName);
Integer loginUserLockNO= 0;
if (loginUserLock!=null){
loginUserLockNO = Integer.valueOf(loginUserLock);
}
//判断密码是否正确
String sm3EncodePassword = sm3PasswordEncoder.encode(password);
if(!sm3PasswordEncoder.matches(password,userInfo.getPassword())){
redisUtils.set("user:lock:"+userName, String.valueOf(++loginUserLockNO),120);
//两分钟内错误登录次数超过5次锁定账户
if (loginUserLockNO>5){
USERS user = new USERS();
user.setUsername(userName);
user.setUserId(userInfo.getUserId());
//锁定用户
user.setState(false);
userMapper.updateByPrimaryKeySelective(user);
}
return null;
}
}catch (Exception e){
throw new BadCredentialsException("验证失败!");
}
// 前后端分离情况下 处理逻辑...
// 更新登录令牌 - 之后访问系统其它接口直接通过token认证用户权限...
return new UsernamePasswordAuthenticationToken(userInfo, password, userInfo.getAuthorities());
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
/**
* 根据用户密码生成秘文
* @param credentials 用户登录密码
* @param salt 盐
* @param hashIterations 1024
* @return
*/
protected Hash hashProvidedCredentials(Object credentials, Object salt, int hashIterations) {
String hashAlgorithmName = "SHA-1";
hashIterations = 1024;
return new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
}
protected boolean equals(Object tokenCredentials, Object accountCredentials) {
if (this.isByteSource(tokenCredentials) && this.isByteSource(accountCredentials)) {
byte[] tokenBytes = this.toBytes(tokenCredentials);
byte[] accountBytes = this.toBytes(accountCredentials);
return Arrays.equals(tokenBytes, accountBytes);
} else {
return accountCredentials.equals(tokenCredentials);
}
}
}
... ...
package com.tianbo.warehouse.security.login;
import org.springframework.stereotype.Component;
@Component
public class PasswordSaltUtils {
/**
* 密码校验
* @return true密码校验通过 false 失败
*/
public static boolean isValidPassword(String LoginPassword, String UserPassword, String Salt){
return true;
}
/**
* 加密前端传递过来的密码
* @param Salt 盐
* @param SaltFromDB 数据库中保存的盐
* @return
*/
public static String encodePassword(String Salt,String SaltFromDB){
return null;
}
/**
* 解码存储到数据库中密码密文的前16位
* @param userPasswordInDB 数据库中用户的密码
* @return
*/
public static byte[] getSalt16(String userPasswordInDB){
byte[] salt = Encodes.decodeHex(userPasswordInDB.substring(0,16));
return salt;
}
/**
* 取存储到数据库中密码密文的后16位
* @param userPasswordInDB 数据库中用户的密码
* @return
*/
public static String getPassword16(String userPasswordInDB){
return userPasswordInDB.substring(16);
}
}
... ...
package com.tianbo.warehouse.security.login;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.UnsupportedEncodingException;
import java.security.Security;
/**
* sm3生成密码摘要
* 需要依赖 Bouncy Castle轻量级密码术包 1.60
*/
public class SM3EncryptUtil {
private static byte[] SECRET_KEY = {101, 87, 99, 10, 34, 45, 77, 76, 98, 13, 12, 18, 73, 84, 91, 93};
public static byte[] hash(byte[] srcData) {
SM3Digest digest = new SM3Digest();
digest.update(srcData, 0, srcData.length);
byte[] hash = new byte[digest.getDigestSize()];
digest.doFinal(hash, 0);
return hash;
}
public static String bytetoString(byte[] digest) {
String str = "";
String tempStr = "";
for (int i = 0; i < digest.length; i++) {
tempStr = (Integer.toHexString(digest[i] & 0xff));
if (tempStr.length() == 1) {
str = str + "0" + tempStr;
} else {
str = str + tempStr;
}
}
return str.toLowerCase();
}
/**
* 密码SM3加密
* @param password
* @return
*/
public static String passwordSm3(String password){
Security.addProvider(new BouncyCastleProvider());
try {
byte[] pwdBytes = password.getBytes("UTF-8");
byte[] pwdDigest = hash(pwdBytes);
return bytetoString(pwdDigest);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
Security.addProvider(new BouncyCastleProvider());
try {
String pwdDigest = passwordSm3("vmvnv1v2VV");
System.out.println(pwdDigest);
} catch (Exception e) {
e.printStackTrace();
}
}
}
... ...
package com.tianbo.warehouse.security.login;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.util.Base64;
/**
* sm4加密工具
* 需要依赖 Bouncy Castle轻量级密码术包 1.60
*/
public class SM4EncryptUtil {
/**
* 密钥, 禁止修改
*/
private static byte[] SECRET_KEY = {101, 87, 99, 10, 34, 45, 77, 76, 98, 13, 12, 18, 73, 84, 91, 93};
/**
* 解密方法
*/
public static byte[] decryptSM4( byte[] cipherText)
throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException,
NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException {
return decryptSM4(SECRET_KEY, cipherText);
}
public static byte[] decryptSM4(byte[] key, byte[] cipherText)
throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException,
NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException {
Cipher cipher = generateEcbCipher("SM4/ECB/PKCS5Padding", Cipher.DECRYPT_MODE, key);
return cipher.doFinal(cipherText);
}
/**
* 解密方法
*/
public static byte[] encryptSM4( byte[] cipherText)
throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException,
NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException {
return encryptSM4(SECRET_KEY, cipherText);
}
public static byte[] encryptSM4(byte[] key, byte[] data)
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException,
NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = generateEcbCipher("SM4/ECB/PKCS5Padding", Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(data);
}
private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key)
throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
InvalidKeyException {
Cipher cipher = Cipher.getInstance(algorithmName, "BC");
Key sm4Key = new SecretKeySpec(key, "SM4");
cipher.init(mode, sm4Key);
return cipher;
}
public String pwd(String pwd){
try {
String encryptPwd = new String(Base64.getEncoder().encode(encryptSM4(pwd.getBytes("UTF-8"))));
return encryptPwd;
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
}
... ...
... ... @@ -4,11 +4,15 @@ import com.github.pagehelper.PageInfo;
import com.tianbo.warehouse.model.ROLE;
import com.tianbo.warehouse.model.RolePermission;
import java.util.List;
public interface RoleService {
PageInfo<ROLE> findAll(int pageNum, int pageSize, String roleName, String type);
public PageInfo<ROLE> orgSelectWithRootNoTree(ROLE role,int pageNum, int pageSize);
List<ROLE> getROLE_anonymousPermList();
int insertSelective(ROLE record);
int setRolePermissoin(RolePermission record);
... ...
... ... @@ -109,6 +109,12 @@ public class RoleServiceImp implements RoleService{
return roleMapper.insertSelective(record);
}
@Override
public List<ROLE> getROLE_anonymousPermList() {
List<ROLE> list = roleMapper.findAll("ROLE_anonymous", null);
return list;
}
@RedisCacheDelTarget(cacheKey = "getUserMenuTreeByUserId")
@Transactional(rollbackFor = Exception.class)
@Override
... ...
package com.tianbo.warehouse;
import com.tianbo.warehouse.security.config.SM3PasswordEncoder;
import com.tianbo.warehouse.security.login.SM4EncryptUtil;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
public class SM3EncodeTest {
@Test
public void encode(){
String password = "vmvnv1v2VV";
SM3PasswordEncoder encoder =new SM3PasswordEncoder();
String encode = encoder.encode(password);
System.out.println("SM3encode = " + encode);
String SM4encode = new SM4EncryptUtil().pwd(password);
System.out.println("SM4encode = " + SM4encode);
}
}
... ...