diff --git a/maku-framework/src/main/java/net/maku/framework/security/third/ThirdAuthenticationProvider.java b/maku-framework/src/main/java/net/maku/framework/security/third/ThirdAuthenticationProvider.java
new file mode 100644
index 0000000..20d3256
--- /dev/null
+++ b/maku-framework/src/main/java/net/maku/framework/security/third/ThirdAuthenticationProvider.java
@@ -0,0 +1,85 @@
+package net.maku.framework.security.third;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.MessageSource;
+import org.springframework.context.MessageSourceAware;
+import org.springframework.context.support.MessageSourceAccessor;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.SpringSecurityMessageSource;
+import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
+import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.util.Assert;
+
+/**
+ * 第三方登录 AuthenticationProvider
+ *
+ * @author 阿沐 babamu@126.com
+ * MAKU
+ */
+public class ThirdAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {
+ protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
+ private final GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
+ private final ThirdUserDetailsService thirdUserDetailsService;
+ private final ThirdOpenIdService thirdOpenIdService;
+
+ public ThirdAuthenticationProvider(ThirdUserDetailsService thirdUserDetailsService, ThirdOpenIdService thirdOpenIdService) {
+ this.thirdUserDetailsService = thirdUserDetailsService;
+ this.thirdOpenIdService = thirdOpenIdService;
+ }
+
+ @Override
+ public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+ Assert.isInstanceOf(ThirdAuthenticationToken.class, authentication,
+ () -> messages.getMessage(
+ "ThirdAuthenticationProvider.onlySupports",
+ "Only ThirdAuthenticationProvider is supported"));
+
+ ThirdAuthenticationToken authenticationToken = (ThirdAuthenticationToken) authentication;
+ ThirdLogin login = (ThirdLogin) authenticationToken.getPrincipal();
+
+ try {
+ // 获取用户 openId
+ String openId = thirdOpenIdService.getOpenId(login);
+ // 获取用户信息
+ UserDetails userDetails = thirdUserDetailsService.loadUserByOpenTypeAndOpenId(login.getOpenType(), openId);
+ if (userDetails == null) {
+ throw new BadCredentialsException("Bad credentials");
+ }
+
+ return createSuccessAuthentication(authentication, userDetails);
+ } catch (UsernameNotFoundException ex) {
+ throw new BadCredentialsException(this.messages
+ .getMessage("ThirdAuthenticationProvider.badCredentials", "Bad credentials"));
+ }
+
+ }
+
+ protected Authentication createSuccessAuthentication(Authentication authentication, UserDetails user) {
+ ThirdAuthenticationToken result = new ThirdAuthenticationToken(user,
+ authoritiesMapper.mapAuthorities(user.getAuthorities()));
+ result.setDetails(authentication.getDetails());
+ return result;
+ }
+
+ @Override
+ public boolean supports(Class> authentication) {
+ return ThirdAuthenticationToken.class.isAssignableFrom(authentication);
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ Assert.notNull(thirdUserDetailsService, "thirdUserDetailsService must not be null");
+ Assert.notNull(thirdOpenIdService, "thirdOpenIdService must not be null");
+ }
+
+ @Override
+ public void setMessageSource(MessageSource messageSource) {
+ this.messages = new MessageSourceAccessor(messageSource);
+ }
+
+}
diff --git a/maku-framework/src/main/java/net/maku/framework/security/third/ThirdAuthenticationToken.java b/maku-framework/src/main/java/net/maku/framework/security/third/ThirdAuthenticationToken.java
new file mode 100644
index 0000000..cf1971b
--- /dev/null
+++ b/maku-framework/src/main/java/net/maku/framework/security/third/ThirdAuthenticationToken.java
@@ -0,0 +1,55 @@
+package net.maku.framework.security.third;
+
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.SpringSecurityCoreVersion;
+import org.springframework.util.Assert;
+
+import java.util.Collection;
+
+/**
+ * 第三方登录 AuthenticationToken
+ *
+ * @author 阿沐 babamu@126.com
+ * MAKU
+ */
+public class ThirdAuthenticationToken extends AbstractAuthenticationToken {
+ private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
+ private final Object principal;
+ private Object credentials;
+
+ public ThirdAuthenticationToken(Object principal) {
+ super(null);
+ this.principal = principal;
+ setAuthenticated(false);
+ }
+
+ public ThirdAuthenticationToken(Object principal, Collection extends GrantedAuthority> authorities) {
+ super(authorities);
+ this.principal = principal;
+ super.setAuthenticated(true);
+ }
+
+ @Override
+ public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
+ Assert.isTrue(!isAuthenticated,
+ "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
+ super.setAuthenticated(false);
+ }
+
+ @Override
+ public Object getCredentials() {
+ return this.credentials;
+ }
+
+ @Override
+ public Object getPrincipal() {
+ return this.principal;
+ }
+
+ @Override
+ public void eraseCredentials() {
+ super.eraseCredentials();
+ this.credentials = null;
+ }
+}
diff --git a/maku-framework/src/main/java/net/maku/framework/security/third/ThirdLogin.java b/maku-framework/src/main/java/net/maku/framework/security/third/ThirdLogin.java
new file mode 100644
index 0000000..69e6f8e
--- /dev/null
+++ b/maku-framework/src/main/java/net/maku/framework/security/third/ThirdLogin.java
@@ -0,0 +1,29 @@
+package net.maku.framework.security.third;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 第三方登录 表单数据
+ *
+ * @author 阿沐 babamu@126.com
+ * MAKU
+ */
+@Data
+public class ThirdLogin implements Serializable {
+ /**
+ * 开放平台类型
+ */
+ private String openType;
+
+ /**
+ * 开放平台Code
+ */
+ private String code;
+
+ /**
+ * state
+ */
+ private String state;
+}
diff --git a/maku-framework/src/main/java/net/maku/framework/security/third/ThirdOpenIdService.java b/maku-framework/src/main/java/net/maku/framework/security/third/ThirdOpenIdService.java
new file mode 100644
index 0000000..d911028
--- /dev/null
+++ b/maku-framework/src/main/java/net/maku/framework/security/third/ThirdOpenIdService.java
@@ -0,0 +1,18 @@
+package net.maku.framework.security.third;
+
+/**
+ * 第三方登录,通过code,获取开放平台用户唯一标识
+ *
+ * @author 阿沐 babamu@126.com
+ * MAKU
+ */
+public interface ThirdOpenIdService {
+
+ /**
+ * 通过code,获取开放平台用户唯一标识
+ *
+ * @param login 第三方登录信息
+ * @return 开放平台用户唯一标识
+ */
+ String getOpenId(ThirdLogin login);
+}
diff --git a/maku-framework/src/main/java/net/maku/framework/security/third/ThirdUserDetailsService.java b/maku-framework/src/main/java/net/maku/framework/security/third/ThirdUserDetailsService.java
new file mode 100644
index 0000000..b3458c7
--- /dev/null
+++ b/maku-framework/src/main/java/net/maku/framework/security/third/ThirdUserDetailsService.java
@@ -0,0 +1,23 @@
+package net.maku.framework.security.third;
+
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+
+/**
+ * 第三方登录,ThirdUserDetailsService
+ *
+ * @author 阿沐 babamu@126.com
+ * MAKU
+ */
+public interface ThirdUserDetailsService {
+
+ /**
+ * 通过开放平台类型和唯一标识,加载用户信息
+ *
+ * @param openType 开放平台类型
+ * @param openId 开放平台唯一标识
+ * @return 用户信息
+ * @throws UsernameNotFoundException 不存在异常
+ */
+ UserDetails loadUserByOpenTypeAndOpenId(String openType, String openId) throws UsernameNotFoundException;
+}