6 changed files with 418 additions and 0 deletions
-
59common/src/main/java/com/canvas/web/annotation/rest/AnonymousPostMapping.java
-
17common/src/main/java/com/canvas/web/config/RsaProperties.java
-
177common/src/main/java/com/canvas/web/utils/RsaUtils.java
-
86system/src/main/java/modules/security/controller/AuthorizationController.java
-
25system/src/main/java/modules/security/service/OnlineUserService.java
-
54system/src/main/java/modules/security/service/dto/OnlineUserDto.java
@ -0,0 +1,59 @@ |
|||
package com.canvas.web.annotation.rest; |
|||
|
|||
|
|||
import com.canvas.web.annotation.AnonymousAccess; |
|||
import org.springframework.core.annotation.AliasFor; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestMethod; |
|||
|
|||
import java.lang.annotation.*; |
|||
|
|||
@AnonymousAccess |
|||
@Target(ElementType.METHOD) |
|||
@Retention(RetentionPolicy.RUNTIME) |
|||
@Documented |
|||
@RequestMapping(method = RequestMethod.POST) |
|||
public @interface AnonymousPostMapping { |
|||
|
|||
/** |
|||
* Alias for {@link RequestMapping#name}. |
|||
*/ |
|||
@AliasFor(annotation = RequestMapping.class) |
|||
String name() default ""; |
|||
|
|||
/** |
|||
* Alias for {@link RequestMapping#value}. |
|||
*/ |
|||
@AliasFor(annotation = RequestMapping.class) |
|||
String[] value() default {}; |
|||
|
|||
/** |
|||
* Alias for {@link RequestMapping#path}. |
|||
*/ |
|||
@AliasFor(annotation = RequestMapping.class) |
|||
String[] path() default {}; |
|||
|
|||
/** |
|||
* Alias for {@link RequestMapping#params}. |
|||
*/ |
|||
@AliasFor(annotation = RequestMapping.class) |
|||
String[] params() default {}; |
|||
|
|||
/** |
|||
* Alias for {@link RequestMapping#headers}. |
|||
*/ |
|||
@AliasFor(annotation = RequestMapping.class) |
|||
String[] headers() default {}; |
|||
|
|||
/** |
|||
* Alias for {@link RequestMapping#consumes}. |
|||
*/ |
|||
@AliasFor(annotation = RequestMapping.class) |
|||
String[] consumes() default {}; |
|||
|
|||
/** |
|||
* Alias for {@link RequestMapping#produces}. |
|||
*/ |
|||
@AliasFor(annotation = RequestMapping.class) |
|||
String[] produces() default {}; |
|||
} |
@ -0,0 +1,17 @@ |
|||
package com.canvas.web.config; |
|||
|
|||
import lombok.Data; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
@Data |
|||
@Component |
|||
public class RsaProperties { |
|||
|
|||
public static String privateKey; |
|||
|
|||
@Value("${rsa.private_key}") |
|||
public void setPrivateKey(String privateKey) { |
|||
RsaProperties.privateKey = privateKey; |
|||
} |
|||
} |
@ -0,0 +1,177 @@ |
|||
package com.canvas.web.utils; |
|||
|
|||
import org.apache.commons.codec.binary.Base64; |
|||
|
|||
import javax.crypto.Cipher; |
|||
import java.security.*; |
|||
import java.security.interfaces.RSAPrivateKey; |
|||
import java.security.interfaces.RSAPublicKey; |
|||
import java.security.spec.PKCS8EncodedKeySpec; |
|||
import java.security.spec.X509EncodedKeySpec; |
|||
|
|||
public class RsaUtils { |
|||
|
|||
private static final String SRC = "123456"; |
|||
|
|||
public static void main(String[] args) throws Exception { |
|||
System.out.println("\n"); |
|||
RsaKeyPair keyPair = generateKeyPair(); |
|||
System.out.println("公钥:" + keyPair.getPublicKey()); |
|||
System.out.println("私钥:" + keyPair.getPrivateKey()); |
|||
System.out.println("\n"); |
|||
test1(keyPair); |
|||
System.out.println("\n"); |
|||
test2(keyPair); |
|||
System.out.println("\n"); |
|||
} |
|||
|
|||
/** |
|||
* 公钥加密私钥解密 |
|||
*/ |
|||
private static void test1(RsaKeyPair keyPair) throws Exception { |
|||
System.out.println("***************** 公钥加密私钥解密开始 *****************"); |
|||
String text1 = encryptByPublicKey(keyPair.getPublicKey(), RsaUtils.SRC); |
|||
String text2 = decryptByPrivateKey(keyPair.getPrivateKey(), text1); |
|||
System.out.println("加密前:" + RsaUtils.SRC); |
|||
System.out.println("加密后:" + text1); |
|||
System.out.println("解密后:" + text2); |
|||
if (RsaUtils.SRC.equals(text2)) { |
|||
System.out.println("解密字符串和原始字符串一致,解密成功"); |
|||
} else { |
|||
System.out.println("解密字符串和原始字符串不一致,解密失败"); |
|||
} |
|||
System.out.println("***************** 公钥加密私钥解密结束 *****************"); |
|||
} |
|||
|
|||
/** |
|||
* 私钥加密公钥解密 |
|||
* @throws Exception / |
|||
*/ |
|||
private static void test2(RsaKeyPair keyPair) throws Exception { |
|||
System.out.println("***************** 私钥加密公钥解密开始 *****************"); |
|||
String text1 = encryptByPrivateKey(keyPair.getPrivateKey(), RsaUtils.SRC); |
|||
String text2 = decryptByPublicKey(keyPair.getPublicKey(), text1); |
|||
System.out.println("加密前:" + RsaUtils.SRC); |
|||
System.out.println("加密后:" + text1); |
|||
System.out.println("解密后:" + text2); |
|||
if (RsaUtils.SRC.equals(text2)) { |
|||
System.out.println("解密字符串和原始字符串一致,解密成功"); |
|||
} else { |
|||
System.out.println("解密字符串和原始字符串不一致,解密失败"); |
|||
} |
|||
System.out.println("***************** 私钥加密公钥解密结束 *****************"); |
|||
} |
|||
|
|||
/** |
|||
* 公钥解密 |
|||
* |
|||
* @param publicKeyText 公钥 |
|||
* @param text 待解密的信息 |
|||
* @return / |
|||
* @throws Exception / |
|||
*/ |
|||
public static String decryptByPublicKey(String publicKeyText, String text) throws Exception { |
|||
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText)); |
|||
KeyFactory keyFactory = KeyFactory.getInstance("RSA"); |
|||
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); |
|||
Cipher cipher = Cipher.getInstance("RSA"); |
|||
cipher.init(Cipher.DECRYPT_MODE, publicKey); |
|||
byte[] result = cipher.doFinal(Base64.decodeBase64(text)); |
|||
return new String(result); |
|||
} |
|||
|
|||
/** |
|||
* 私钥加密 |
|||
* |
|||
* @param privateKeyText 私钥 |
|||
* @param text 待加密的信息 |
|||
* @return / |
|||
* @throws Exception / |
|||
*/ |
|||
public static String encryptByPrivateKey(String privateKeyText, String text) throws Exception { |
|||
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText)); |
|||
KeyFactory keyFactory = KeyFactory.getInstance("RSA"); |
|||
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); |
|||
Cipher cipher = Cipher.getInstance("RSA"); |
|||
cipher.init(Cipher.ENCRYPT_MODE, privateKey); |
|||
byte[] result = cipher.doFinal(text.getBytes()); |
|||
return Base64.encodeBase64String(result); |
|||
} |
|||
|
|||
/** |
|||
* 私钥解密 |
|||
* |
|||
* @param privateKeyText 私钥 |
|||
* @param text 待解密的文本 |
|||
* @return / |
|||
* @throws Exception / |
|||
*/ |
|||
public static String decryptByPrivateKey(String privateKeyText, String text) throws Exception { |
|||
PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText)); |
|||
KeyFactory keyFactory = KeyFactory.getInstance("RSA"); |
|||
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5); |
|||
Cipher cipher = Cipher.getInstance("RSA"); |
|||
cipher.init(Cipher.DECRYPT_MODE, privateKey); |
|||
byte[] result = cipher.doFinal(Base64.decodeBase64(text)); |
|||
return new String(result); |
|||
} |
|||
|
|||
/** |
|||
* 公钥加密 |
|||
* |
|||
* @param publicKeyText 公钥 |
|||
* @param text 待加密的文本 |
|||
* @return / |
|||
*/ |
|||
public static String encryptByPublicKey(String publicKeyText, String text) throws Exception { |
|||
X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText)); |
|||
KeyFactory keyFactory = KeyFactory.getInstance("RSA"); |
|||
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2); |
|||
Cipher cipher = Cipher.getInstance("RSA"); |
|||
cipher.init(Cipher.ENCRYPT_MODE, publicKey); |
|||
byte[] result = cipher.doFinal(text.getBytes()); |
|||
return Base64.encodeBase64String(result); |
|||
} |
|||
|
|||
/** |
|||
* 构建RSA密钥对 |
|||
* |
|||
* @return / |
|||
* @throws NoSuchAlgorithmException / |
|||
*/ |
|||
public static RsaKeyPair generateKeyPair() throws NoSuchAlgorithmException { |
|||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); |
|||
keyPairGenerator.initialize(1024); |
|||
KeyPair keyPair = keyPairGenerator.generateKeyPair(); |
|||
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic(); |
|||
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate(); |
|||
String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded()); |
|||
String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded()); |
|||
return new RsaKeyPair(publicKeyString, privateKeyString); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* RSA密钥对对象 |
|||
*/ |
|||
public static class RsaKeyPair { |
|||
|
|||
private final String publicKey; |
|||
private final String privateKey; |
|||
|
|||
public RsaKeyPair(String publicKey, String privateKey) { |
|||
this.publicKey = publicKey; |
|||
this.privateKey = privateKey; |
|||
} |
|||
|
|||
public String getPublicKey() { |
|||
return publicKey; |
|||
} |
|||
|
|||
public String getPrivateKey() { |
|||
return privateKey; |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
@ -0,0 +1,86 @@ |
|||
package modules.security.controller; |
|||
|
|||
|
|||
import com.canvas.web.annotation.rest.AnonymousPostMapping; |
|||
import com.canvas.web.config.RsaProperties; |
|||
import com.canvas.web.exception.BaseException; |
|||
import com.canvas.web.utils.RedisUtils; |
|||
import com.canvas.web.utils.RsaUtils; |
|||
import com.canvas.web.utils.StringUtils; |
|||
import io.swagger.annotations.Api; |
|||
import io.swagger.annotations.ApiOperation; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import modules.security.config.bean.LoginProperties; |
|||
import modules.security.config.bean.SecurityProperties; |
|||
import modules.security.security.TokenProvider; |
|||
import modules.security.service.OnlineUserService; |
|||
import modules.security.service.dto.AuthUserDto; |
|||
import modules.security.service.dto.JwtUserDto; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
|||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; |
|||
import org.springframework.security.core.Authentication; |
|||
import org.springframework.security.core.context.SecurityContextHolder; |
|||
import org.springframework.validation.annotation.Validated; |
|||
import org.springframework.web.bind.annotation.RequestBody; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import javax.annotation.Resource; |
|||
import javax.servlet.http.HttpServletRequest; |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
@Slf4j |
|||
@RestController |
|||
@RequestMapping("/auth") |
|||
@RequiredArgsConstructor |
|||
@Api(tags = "系统:系统授权接口") |
|||
public class AuthorizationController { |
|||
|
|||
private final SecurityProperties properties; |
|||
private final RedisUtils redisUtils; |
|||
private final OnlineUserService onlineUserService; |
|||
private final TokenProvider tokenProvider; |
|||
private final AuthenticationManagerBuilder authenticationManagerBuilder; |
|||
|
|||
@Resource |
|||
private LoginProperties loginProperties; |
|||
|
|||
|
|||
@ApiOperation("登录授权") |
|||
@AnonymousPostMapping(value = "/login") |
|||
public ResponseEntity<Object> login(@Validated @RequestBody AuthUserDto authUser, HttpServletRequest request) throws Exception { |
|||
// 密码解密 |
|||
String password = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey, authUser.getPassword()); |
|||
// 查询验证码 |
|||
String code = (String) redisUtils.get(authUser.getUuid()); |
|||
// 清除验证码 |
|||
redisUtils.del(authUser.getUuid()); |
|||
if (StringUtils.isBlank(code)) { |
|||
throw new BaseException("验证码不存在或已过期"); |
|||
} |
|||
if (StringUtils.isBlank(authUser.getCode()) || !authUser.getCode().equalsIgnoreCase(code)) { |
|||
throw new BaseException("验证码错误"); |
|||
} |
|||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(authUser.getUsername(), password); |
|||
Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); |
|||
SecurityContextHolder.getContext().setAuthentication(authentication); |
|||
// 生成令牌 |
|||
String token = tokenProvider.createToken(authentication); |
|||
final JwtUserDto jwtUserDto = (JwtUserDto) authentication.getPrincipal(); |
|||
// 保存在线信息 |
|||
onlineUserService.save(jwtUserDto, token, request); |
|||
// 返回 token 与 用户信息 |
|||
Map<String, Object> authInfo = new HashMap<String, Object>(2) {{ |
|||
put("token", properties.getTokenStartWith() + token); |
|||
put("user", jwtUserDto); |
|||
}}; |
|||
if (loginProperties.isSingleLogin()) { |
|||
//踢掉之前已经登录的token |
|||
onlineUserService.checkLoginOnUser(authUser.getUsername(), token); |
|||
} |
|||
return ResponseEntity.ok(authInfo); |
|||
} |
|||
} |
@ -0,0 +1,54 @@ |
|||
package modules.security.service.dto; |
|||
|
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
|
|||
import java.util.Date; |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
@NoArgsConstructor |
|||
public class OnlineUserDto { |
|||
|
|||
/** |
|||
* 用户名 |
|||
*/ |
|||
private String userName; |
|||
|
|||
/** |
|||
* 昵称 |
|||
*/ |
|||
private String nickName; |
|||
|
|||
/** |
|||
* 岗位 |
|||
*/ |
|||
private String dept; |
|||
|
|||
/** |
|||
* 浏览器 |
|||
*/ |
|||
private String browser; |
|||
|
|||
/** |
|||
* IP |
|||
*/ |
|||
private String ip; |
|||
|
|||
/** |
|||
* 地址 |
|||
*/ |
|||
private String address; |
|||
|
|||
/** |
|||
* token |
|||
*/ |
|||
private String key; |
|||
|
|||
/** |
|||
* 登录时间 |
|||
*/ |
|||
private Date loginTime; |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue