初始化提交

This commit is contained in:
2021-01-20 18:30:23 +08:00
commit 3eb965f380
208 changed files with 8103 additions and 0 deletions

16
auth/authorization-server/.gitignore vendored Normal file
View File

@ -0,0 +1,16 @@
target/
logs/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

View File

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>business.chaoran</groupId>
<artifactId>authorization-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<!-- <packaging>jar</packaging>-->
<name>authorization-server</name>
<description>Demo Oauth2 project for Spring Cloud Oauth2 Authorization Server</description>
<parent>
<groupId>business.chaoran</groupId>
<artifactId>auth</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>business.chaoran</groupId>
<artifactId>web</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!--oauth2认证-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-security</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.0.pr1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<!-- 独立运行依赖-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-web</artifactId>-->
<!-- </dependency>-->
<!-- tomcat容器部署运行依赖-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.4.RELEASE</version>
<executions>
<execution>
<goals>
<goal>build-info</goal>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
<finalName>authorization-server</finalName>
</build>
</project>

View File

@ -0,0 +1,23 @@
package com.springboot.auth.authorization;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class Oauth2AuthorizationApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Oauth2AuthorizationApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Oauth2AuthorizationApplication.class);
}
}

View File

@ -0,0 +1,179 @@
package com.springboot.auth.authorization.config;
import com.google.common.collect.Lists;
import com.springboot.auth.authorization.exception.CustomWebResponseExceptionTranslator;
import com.springboot.auth.authorization.oauth2.enhancer.CustomTokenEnhancer;
import com.springboot.auth.authorization.oauth2.granter.MobileTokenGranter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.approval.Approval;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.InMemoryApprovalStore;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import java.util.Arrays;
import java.util.List;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
// @Qualifier("dataSource")
// @Autowired
// DataSource dataSource;
@Autowired
@Qualifier("userDetailsService")
UserDetailsService userDetailsService;
/**
* jwt 对称加密密钥
*/
@Value("${spring.security.oauth2.jwt.signingKey}")
private String signingKey;
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
// 支持将client参数放在header或body中
oauthServer.allowFormAuthenticationForClients();
//认证策略默认为denyAll()
oauthServer.tokenKeyAccess("isAuthenticated()")
.checkTokenAccess("permitAll()");
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 配置客户端信息从数据库中读取对应oauth_client_details表
// clients.jdbc(dataSource);
clients.inMemory().withClient("test_client").secret("$2a$10$2szDKjvKHJCWE6YQNznogOeQF3USZHmCYj1fG7YbfK.vnTgNKLzri").scopes("read")
.authorizedGrantTypes("client_credentials", "authorization_code", "mobile", "password", "refresh_token")
.redirectUris("http://www.baidu.com").accessTokenValiditySeconds(3600).refreshTokenValiditySeconds(3600);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
// 配置token的数据源、自定义的tokenServices等信息,配置身份认证器配置认证方式TokenStoreTokenGranterOAuth2RequestFactory
endpoints.tokenStore(tokenStore())
.authorizationCodeServices(authorizationCodeServices())
.approvalStore(approvalStore())
.exceptionTranslator(customExceptionTranslator())
.tokenEnhancer(tokenEnhancerChain())
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService)
//update by joe_chen add granter
.tokenGranter(tokenGranter(endpoints));
}
/**
* 自定义OAuth2异常处理
*
* @return CustomWebResponseExceptionTranslator
*/
@Bean
public WebResponseExceptionTranslator<OAuth2Exception> customExceptionTranslator() {
return new CustomWebResponseExceptionTranslator();
}
/**
* 授权信息持久化实现
* 密码模式无用
* @return JdbcApprovalStore
*/
@Bean
public ApprovalStore approvalStore() {
InMemoryApprovalStore memoryApprovalStore = new InMemoryApprovalStore();
Approval approval = new Approval("1", "test_client", "read", 3600, Approval.ApprovalStatus.APPROVED);
memoryApprovalStore.addApprovals(Arrays.asList(approval));
// return new JdbcApprovalStore(dataSource);
return memoryApprovalStore;
}
/**
* 授权码模式持久化授权码code
* 密码模式无用
* @return JdbcAuthorizationCodeServices
*/
@Bean
protected AuthorizationCodeServices authorizationCodeServices() {
// 授权码存储等处理方式类使用jdbc操作oauth_code表
InMemoryAuthorizationCodeServices authorizationCodeServices = new InMemoryAuthorizationCodeServices();
// return new JdbcAuthorizationCodeServices(dataSource);
return authorizationCodeServices;
}
/**
* token的持久化
*
* @return JwtTokenStore
*/
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
/**
* 自定义token
*
* @return tokenEnhancerChain
*/
@Bean
public TokenEnhancerChain tokenEnhancerChain() {
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(new CustomTokenEnhancer(), accessTokenConverter()));
return tokenEnhancerChain;
}
/**
* jwt token的生成配置
*
* @return
*/
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(signingKey);
return converter;
}
/**
* 配置自定义的granter,手机号验证码登陆
*
* @param endpoints
* @return
*/
public TokenGranter tokenGranter(final AuthorizationServerEndpointsConfigurer endpoints) {
List<TokenGranter> granters = Lists.newArrayList(endpoints.getTokenGranter());
granters.add(new MobileTokenGranter(
authenticationManager,
endpoints.getTokenServices(),
endpoints.getClientDetailsService(),
endpoints.getOAuth2RequestFactory()));
return new CompositeTokenGranter(granters);
}
}

View File

@ -0,0 +1,21 @@
package com.springboot.auth.authorization.config;
/*
**********************************************
* DATE PERSON REASON
* 2020/12/7 FXY Created
**********************************************
*/
import com.springboot.cloud.common.web.interceptor.FeignBasicAuthRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class InterceptConfig {
@Bean
public FeignBasicAuthRequestInterceptor interceptor(){
return new FeignBasicAuthRequestInterceptor();
}
}

View File

@ -0,0 +1,56 @@
package com.springboot.auth.authorization.config;
/*
**********************************************
* DATE PERSON REASON
* 2020-12-24 FXY Created
**********************************************
*/
import com.alibaba.cloud.nacos.registry.NacosAutoServiceRegistration;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Configuration;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.Query;
import java.lang.management.ManagementFactory;
import java.util.Set;
@Configuration
@Slf4j
public class NacosRegisterConfig implements ApplicationRunner {
@Autowired(required = false)
private NacosAutoServiceRegistration registration;
private Integer port;
public NacosRegisterConfig() {
try {
this.port = Integer.parseInt(getTomcatPort());
} catch (Exception e) {
log.error("获取tomcat端口出错了原因{}", e.toString());
}
}
@Override
public void run(ApplicationArguments args) {
if (registration != null && port != null) {
registration.setPort(port);
registration.start();
}
}
//获取tomcat端口
private String getTomcatPort() throws Exception {
MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer();
Set<ObjectName> objectNames = beanServer.queryNames(new ObjectName("*:type=Connector,*"), Query.match(Query.attr("protocol"), Query.value("HTTP/1.1")));
String port = objectNames.iterator().next().getKeyProperty("port");
return port;
}
}

View File

@ -0,0 +1,83 @@
package com.springboot.auth.authorization.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.springboot.auth.authorization.oauth2.granter.MobileAuthenticationProvider;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Configuration
@EnableWebSecurity
public class WebServerSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("userDetailsService")
private UserDetailsService userDetailsService;
@Autowired
@Qualifier("mobileUserDetailsService")
private UserDetailsService mobileUserDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests()
.antMatchers("/actuator/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().permitAll();
}
/**
* 注入自定义的userDetailsService实现获取用户信息设置密码加密方式
*
* @param authenticationManagerBuilder
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
// 设置手机验证码登陆的AuthenticationProvider
authenticationManagerBuilder.authenticationProvider(mobileAuthenticationProvider());
}
/**
* 将 AuthenticationManager 注册为 bean , 方便配置 oauth server 的时候使用
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 创建手机验证码登陆的AuthenticationProvider
*
* @return mobileAuthenticationProvider
*/
@Bean
public MobileAuthenticationProvider mobileAuthenticationProvider() {
MobileAuthenticationProvider mobileAuthenticationProvider = new MobileAuthenticationProvider(this.mobileUserDetailsService);
mobileAuthenticationProvider.setPasswordEncoder(passwordEncoder());
return mobileAuthenticationProvider;
}
}

View File

@ -0,0 +1,24 @@
package com.springboot.auth.authorization.entity;
/*
**********************************************
* DATE PERSON REASON
* 2020-12-29 FXY Created
**********************************************
*/
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class Company {
private String companyId;
private String userId;
private String organizationId;
private String empNo;
private String position;
private Integer isDefault;
private Integer state;
private String mobile;
}

View File

@ -0,0 +1,31 @@
package com.springboot.auth.authorization.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String id;
private String name;
private Date registryTime;
private String identity;
private String nickName;
private String photo;
private String lastModifier;
private Date lastModifyTime;
private Double state;
private String mobile;
private String email;
private String introduce;
private String avatar;
private String signature;
private String password;
private String username;
}

View File

@ -0,0 +1,38 @@
package com.springboot.auth.authorization.exception;
import com.springboot.cloud.common.core.exception.ErrorType;
import lombok.Getter;
@Getter
public enum AuthErrorType implements ErrorType {
INVALID_REQUEST("040001", "无效请求"),
INVALID_CLIENT("040002", "无效client_id"),
INVALID_GRANT("040003", "无效授权"),
INVALID_SCOPE("040004", "无效scope"),
INVALID_TOKEN("040005", "无效token"),
INSUFFICIENT_SCOPE("040010", "授权不足"),
REDIRECT_URI_MISMATCH("040020", "redirect url不匹配"),
ACCESS_DENIED("040030", "拒绝访问"),
METHOD_NOT_ALLOWED("040040", "不支持该方法"),
SERVER_ERROR("040050", "权限服务错误"),
UNAUTHORIZED_CLIENT("040060", "未授权客户端"),
UNAUTHORIZED("040061", "未授权"),
UNSUPPORTED_RESPONSE_TYPE("040070", " 支持的响应类型"),
UNSUPPORTED_GRANT_TYPE("040071", "不支持的授权类型");
/**
* 错误类型码
*/
private String code;
/**
* 错误类型描述信息
*/
private String mesg;
AuthErrorType(String code, String mesg) {
this.code = code;
this.mesg = mesg;
}
}

View File

@ -0,0 +1,20 @@
package com.springboot.auth.authorization.exception;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.springboot.cloud.common.core.entity.vo.Result;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
@EqualsAndHashCode(callSuper = true)
@Data
@JsonSerialize(using = CustomOauthExceptionSerializer.class)
class CustomOauthException extends OAuth2Exception {
private final Result result;
CustomOauthException(OAuth2Exception oAuth2Exception) {
super(oAuth2Exception.getSummary(), oAuth2Exception);
this.result = Result.fail(AuthErrorType.valueOf(oAuth2Exception.getOAuth2ErrorCode().toUpperCase()), oAuth2Exception);
}
}

View File

@ -0,0 +1,18 @@
package com.springboot.auth.authorization.exception;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;
public class CustomOauthExceptionSerializer extends StdSerializer<CustomOauthException> {
public CustomOauthExceptionSerializer() {
super(CustomOauthException.class);
}
@Override
public void serialize(CustomOauthException value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeObject(value.getResult());
}
}

View File

@ -0,0 +1,16 @@
package com.springboot.auth.authorization.exception;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
public class CustomWebResponseExceptionTranslator implements WebResponseExceptionTranslator<OAuth2Exception> {
@Override
public ResponseEntity<OAuth2Exception> translate(Exception e) {
OAuth2Exception oAuth2Exception = (OAuth2Exception) e;
return ResponseEntity.status(oAuth2Exception.getHttpErrorCode())
.body(new CustomOauthException(oAuth2Exception));
}
}

View File

@ -0,0 +1,11 @@
package com.springboot.auth.authorization.exception;
import com.springboot.cloud.common.web.exception.DefaultGlobalExceptionHandlerAdvice;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandlerAdvice extends DefaultGlobalExceptionHandlerAdvice {
}

View File

@ -0,0 +1,49 @@
package com.springboot.auth.authorization.oauth2;
import com.springboot.auth.authorization.entity.Company;
import com.springboot.auth.authorization.entity.User;
import com.springboot.auth.authorization.oauth2.authority.CustomGrantedAuthority;
import com.springboot.auth.authorization.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Slf4j
@Service("userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserService userService;
@Override
public UserDetails loadUserByUsername(String payload) {
User user = userService.getUserByUsernameOrMobile(payload);
log.info("load user by username :{}", user.toString());
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(), //加了密的密码
user.getState() == 1, //账号是否可用
user.getState() == 1, //账号未过期
true, //密码未过期
user.getState() == 1, //账户未锁定
this.obtainGrantedCompany(user));
}
/**
* 获得登录者所有的公司信息
*
* @return
*/
protected Set<CustomGrantedAuthority> obtainGrantedCompany(User user) {
List<Company> companies = userService.getUserAllCompany(user.getId());
return companies.stream().map(companyUser -> new CustomGrantedAuthority(companyUser.getCompanyId(), companyUser.getIsDefault() == 1)).collect(Collectors.toSet());
}
}

View File

@ -0,0 +1,42 @@
package com.springboot.auth.authorization.oauth2;
import com.springboot.auth.authorization.entity.User;
import com.springboot.auth.authorization.provider.SmsCodeProvider;
import com.springboot.auth.authorization.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import java.util.Collections;
/**
* 手机验证码登陆, 用户相关获取
*/
@Slf4j
@Service("mobileUserDetailsService")
public class MobileUserDetailsService extends CustomUserDetailsService {
@Autowired
private UserService userService;
@Autowired
private SmsCodeProvider smsCodeProvider;
@Override
public UserDetails loadUserByUsername(String payload) {
User user = userService.getUserByUsernameOrMobile(payload);
log.info("load user by mobile:{}", user.toString());
// 如果为mobile模式从短信服务中获取验证码动态密码
String credentials = smsCodeProvider.getSmsCode(payload, "LOGIN");
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
credentials,
user.getState() == 1 ? true : false,
user.getState() == 1 ? true : false,
user.getState() == 1 ? true : false,
user.getState() == 1 ? true : false,
super.obtainGrantedCompany(user));
}
}

View File

@ -0,0 +1,36 @@
package com.springboot.auth.authorization.oauth2.authority;
/*
**********************************************
* DATE PERSON REASON
* 2021-01-05 FXY Created
**********************************************
*/
import lombok.AllArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
/**
* 根据getter方法进行序列化的
*/
@AllArgsConstructor
public class CustomGrantedAuthority implements GrantedAuthority {
private final String company;
private boolean isDefault;
/**
* 后期可换为角色编号
*
* @return
*/
@Override
public String getAuthority() {
return company;
}
public boolean isDefault() {
return isDefault;
}
}

View File

@ -0,0 +1,25 @@
package com.springboot.auth.authorization.oauth2.enhancer;
import com.google.common.collect.Maps;
import com.springboot.auth.authorization.oauth2.authority.CustomGrantedAuthority;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class CustomTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
Map<String, Object> additionalInfo = Maps.newHashMap();
additionalInfo.put("companies", authentication.getAuthorities());
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
return accessToken;
}
}

View File

@ -0,0 +1,16 @@
package com.springboot.auth.authorization.oauth2.granter;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.userdetails.UserDetailsService;
public class MobileAuthenticationProvider extends DaoAuthenticationProvider {
public MobileAuthenticationProvider(UserDetailsService userDetailsService) {
super.setUserDetailsService(userDetailsService);
}
@Override
public boolean supports(Class<?> authentication) {
return MobileAuthenticationToken.class.isAssignableFrom(authentication);
}
}

View File

@ -0,0 +1,11 @@
package com.springboot.auth.authorization.oauth2.granter;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
public class MobileAuthenticationToken extends UsernamePasswordAuthenticationToken {
public MobileAuthenticationToken(Authentication authenticationToken) {
super(authenticationToken.getPrincipal(), authenticationToken.getCredentials());
}
}

View File

@ -0,0 +1,53 @@
package com.springboot.auth.authorization.oauth2.granter;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import java.util.LinkedHashMap;
import java.util.Map;
public class MobileTokenGranter extends ResourceOwnerPasswordTokenGranter {
private static final String GRANT_TYPE = "mobile";
private AuthenticationManager authenticationManager;
public MobileTokenGranter(AuthenticationManager authenticationManager,
AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService,
OAuth2RequestFactory requestFactory) {
super(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
this.authenticationManager = authenticationManager;
}
@Override
protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
Map<String, String> parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters());
String username = parameters.get("no");
String password = parameters.get("password");
// Protect from downstream leaks of password
parameters.remove("no");
Authentication userAuth = new UsernamePasswordAuthenticationToken(username, password);
MobileAuthenticationToken mobileAuthenticationToken = new MobileAuthenticationToken(userAuth);
((AbstractAuthenticationToken) userAuth).setDetails(parameters);
try {
userAuth = this.authenticationManager.authenticate(mobileAuthenticationToken);
} catch (AccountStatusException ase) {
//covers expired, locked, disabled cases (mentioned in section 5.2, draft 31)
throw new InvalidGrantException(ase.getMessage());
} catch (BadCredentialsException e) {
// If the username/password are wrong the spec says we should send 400/invalid grant
throw new InvalidGrantException(e.getMessage());
}
if (userAuth == null || !userAuth.isAuthenticated()) {
throw new InvalidGrantException("Could not authenticate user: " + username);
}
OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
return new OAuth2Authentication(storedOAuth2Request, mobileAuthenticationToken);
}
}

View File

@ -0,0 +1,21 @@
package com.springboot.auth.authorization.provider;
import com.springboot.auth.authorization.entity.Company;
import com.springboot.auth.authorization.entity.User;
import com.springboot.cloud.common.core.entity.vo.Result;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@FeignClient(name = "organization", fallback = OrganizationProviderFallback.class,path = "organization")
//@FeignClient(name = "organization", fallback = OrganizationProviderFallback.class)
public interface OrganizationProvider {
@GetMapping(value = "/user/getUserByUsernameOrMobile")
Result<User> getUserByUsernameOrMobile(@RequestParam("payload")String payload);
@GetMapping(value = "/company/getUserAllCompany")
Result<List<Company>> getUserAllCompany(@RequestParam("userId")String userId);
}

View File

@ -0,0 +1,23 @@
package com.springboot.auth.authorization.provider;
import com.springboot.auth.authorization.entity.Company;
import com.springboot.auth.authorization.entity.User;
import com.springboot.cloud.common.core.entity.vo.Result;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.List;
@Component
public class OrganizationProviderFallback implements OrganizationProvider {
@Override
public Result<User> getUserByUsernameOrMobile(String payload) {
return Result.success(new User());
}
@Override
public Result<List<Company>> getUserAllCompany(String userId) {
return Result.success(new HashSet<Company>());
}
}

View File

@ -0,0 +1,19 @@
package com.springboot.auth.authorization.provider;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
/**
* todo 实现短信验证码的服务
*/
//@FeignClient(name = "sms", fallback = OrganizationProviderFallback.class,path="sms")
public interface SmsCodeProvider {
/**
* @param mobile
* @return
*/
@GetMapping(value = "/sms/{mobile}")
String getSmsCode(@PathVariable("mobile") String mobile, @RequestParam("businessType") String businessType);
}

View File

@ -0,0 +1,18 @@
package com.springboot.auth.authorization.provider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
@Component
public class SmsCodeProviderFallback implements SmsCodeProvider {
@Autowired
PasswordEncoder passwordEncoder;
@Override
public String getSmsCode(String mobile, String businessType) {
// 该类为mock, 目前暂时没有sms的服务
return passwordEncoder.encode("123456");
}
}

View File

@ -0,0 +1,22 @@
package com.springboot.auth.authorization.service;
import com.springboot.auth.authorization.entity.Company;
import com.springboot.auth.authorization.entity.User;
import java.util.List;
public interface UserService {
/**
* 通过账号或者手机号得到用户信息
* @param payload 账号或者手机号
* @return
*/
User getUserByUsernameOrMobile(String payload);
/**
* 通过用户编号得到所有所属公司
*/
List<Company> getUserAllCompany(String userId);
}

View File

@ -0,0 +1,27 @@
package com.springboot.auth.authorization.service.impl;
import com.springboot.auth.authorization.entity.Company;
import com.springboot.auth.authorization.entity.User;
import com.springboot.auth.authorization.provider.OrganizationProvider;
import com.springboot.auth.authorization.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private OrganizationProvider organizationProvider;
@Override
public User getUserByUsernameOrMobile(String payload) {
return organizationProvider.getUserByUsernameOrMobile(payload).getData();
}
@Override
public List<Company> getUserAllCompany(String userId) {
return organizationProvider.getUserAllCompany(userId).getData();
}
}

View File

@ -0,0 +1,15 @@
package com.springboot.auth.authorization;
import org.junit.Test;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
public class ApplicationTests {
@Test
public void contextLoads() {
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
System.out.println(passwordEncoder.encode("test_secret"));
}
}