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