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 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; +}