From: 刘洪青 Date: Fri, 20 Sep 2019 02:18:03 +0000 (+0800) Subject: feat: 增加用户登录时,从后端服务接口获取帐号、角色等信息 X-Git-Tag: v0.0.1^2~28 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=d3a55d4d36e95d118f57a4a5275b1cd1e1e283dd;p=institute%2Fsw-backend.git feat: 增加用户登录时,从后端服务接口获取帐号、角色等信息 --- diff --git a/gateway/pom.xml b/gateway/pom.xml index 86dfd32..f7606ed 100644 --- a/gateway/pom.xml +++ b/gateway/pom.xml @@ -58,30 +58,19 @@ - - - - diff --git a/gateway/src/main/java/com/supwisdom/institute/backend/gateway/Application.java b/gateway/src/main/java/com/supwisdom/institute/backend/gateway/Application.java index f837894..adc1582 100644 --- a/gateway/src/main/java/com/supwisdom/institute/backend/gateway/Application.java +++ b/gateway/src/main/java/com/supwisdom/institute/backend/gateway/Application.java @@ -25,12 +25,6 @@ import static org.springframework.web.cors.CorsConfiguration.ALL; @EnableCustomExceptionHandler -//@EnableInfrasOnlineDoc - -//@EnableInfrasCasSecurity - -//@EnableInfrasBasicApi - @EnableInfrasJWTWebFluxApi @EnableInfrasBasicWebFluxApi public class Application { diff --git a/gateway/src/main/java/com/supwisdom/institute/backend/gateway/authn/model/Account.java b/gateway/src/main/java/com/supwisdom/institute/backend/gateway/authn/model/Account.java new file mode 100644 index 0000000..38f38d5 --- /dev/null +++ b/gateway/src/main/java/com/supwisdom/institute/backend/gateway/authn/model/Account.java @@ -0,0 +1,70 @@ +package com.supwisdom.institute.backend.gateway.authn.model; + +import lombok.Getter; +import lombok.Setter; + +import com.supwisdom.institute.backend.common.framework.model.ABaseModel; + +@Getter +@Setter +public class Account extends ABaseModel { + + /** + * + */ + private static final long serialVersionUID = -4889952442290543101L; + + private String id; + + /** + * 用户名 + */ + private String username; + + /** + * 密码 + */ + private String password; + + /** + * 是否可用,1 可用,0 不可用,默认:1 + */ + private Boolean enabled; + /** + * 账号未过期,1 未过期,0 过期,默认:1 + */ + private Boolean accountNonExpired; + /** + * 账号未锁定,1 未锁定,0 锁定,默认:1 + */ + private Boolean accountNonLocked; + /** + * 密码未过期,1 未过期,0 过期,默认:1 + */ + private Boolean credentialsNonExpired; + + /** + * 姓名 + */ + private String name; + + /** + * 备注 + */ + private String memo; + + /** + * 状态(1 启用,0 停用) + */ + private String status; + + /** + * 登录手机 + */ + private String mobile; + /** + * 登录邮箱 + */ + private String email; + +} diff --git a/gateway/src/main/java/com/supwisdom/institute/backend/gateway/authn/model/Permission.java b/gateway/src/main/java/com/supwisdom/institute/backend/gateway/authn/model/Permission.java new file mode 100644 index 0000000..0d5c72d --- /dev/null +++ b/gateway/src/main/java/com/supwisdom/institute/backend/gateway/authn/model/Permission.java @@ -0,0 +1,64 @@ +package com.supwisdom.institute.backend.gateway.authn.model; + +import lombok.Getter; +import lombok.Setter; + +import com.supwisdom.institute.backend.common.framework.model.ABaseModel; + +@Getter +@Setter +public class Permission extends ABaseModel { + + /** + * + */ + private static final long serialVersionUID = -3042842657207449148L; + + private String id; + + /** + * 代码 + */ + private String code; + + /** + * 名称 + */ + private String name; + + /** + * 备注 + */ + private String memo; + + /** + * 状态(1 启用,0 停用) + */ + private String status; + + /** + * 类型(1 应用,2 菜单,3 操作) + */ + private String type; + + /** + * URL地址 + */ + private String url; + + /** + * 系统ID + */ + private String applicationId; + + /** + * 父级ID + */ + private String parentId; + + /** + * 排序 + */ + private Integer order; + +} diff --git a/gateway/src/main/java/com/supwisdom/institute/backend/gateway/authn/model/Role.java b/gateway/src/main/java/com/supwisdom/institute/backend/gateway/authn/model/Role.java new file mode 100644 index 0000000..034ff84 --- /dev/null +++ b/gateway/src/main/java/com/supwisdom/institute/backend/gateway/authn/model/Role.java @@ -0,0 +1,39 @@ +package com.supwisdom.institute.backend.gateway.authn.model; + +import lombok.Getter; +import lombok.Setter; + +import com.supwisdom.institute.backend.common.framework.model.ABaseModel; + +@Getter +@Setter +public class Role extends ABaseModel { + + /** + * + */ + private static final long serialVersionUID = -8551951601186240995L; + + private String id; + + /** + * 代码 + */ + private String code; + + /** + * 名称 + */ + private String name; + + /** + * 备注 + */ + private String memo; + + /** + * 状态(1 启用,0 停用) + */ + private String status; + +} diff --git a/gateway/src/main/java/com/supwisdom/institute/backend/gateway/authn/remote/configuration/AuthnAccountRestTemplateConfig.java b/gateway/src/main/java/com/supwisdom/institute/backend/gateway/authn/remote/configuration/AuthnAccountRestTemplateConfig.java new file mode 100644 index 0000000..5e98c4a --- /dev/null +++ b/gateway/src/main/java/com/supwisdom/institute/backend/gateway/authn/remote/configuration/AuthnAccountRestTemplateConfig.java @@ -0,0 +1,92 @@ +package com.supwisdom.institute.backend.gateway.authn.remote.configuration; + +import javax.net.ssl.SSLContext; + +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.ssl.SSLContexts; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.util.ResourceUtils; +import org.springframework.web.client.RestTemplate; + +@Configuration +public class AuthnAccountRestTemplateConfig { + + @Bean + public ClientHttpRequestFactory simpleClientHttpRequestFactory( + @Value("${sw-backend-base-api.client-auth.enabled:false}") boolean enabled, + @Value("${sw-backend-base-api.client-auth.key-password:}") String keyPassword, + @Value("${sw-backend-base-api.client-auth.key-store:}") String keyStore, + @Value("${sw-backend-base-api.client-auth.key-store-password:}") String keyStorePassword, + @Value("${sw-backend-base-api.client-auth.trust-store:}") String trustStore, + @Value("${sw-backend-base-api.client-auth.trust-store-password:}") String trustStorePassword + ) { + if (!enabled) { + SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); + factory.setReadTimeout(5000);// 单位为ms + factory.setConnectTimeout(5000);// 单位为ms + return factory; + } + + if (keyStore == null || keyStore.isEmpty()) { + SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); + factory.setReadTimeout(5000);// 单位为ms + factory.setConnectTimeout(5000);// 单位为ms + return factory; + } else { + try { + SSLContextBuilder sslContextBuilder = SSLContexts.custom(); + if (trustStore == null || trustStore.isEmpty()) { + } else { + sslContextBuilder +// .loadTrustMaterial(TrustAllStrategy.INSTANCE) + .loadTrustMaterial( + ResourceUtils.getFile(trustStore), + trustStorePassword.toCharArray() + ); + } + + sslContextBuilder + .loadKeyMaterial( + ResourceUtils.getFile(keyStore), + keyStorePassword.toCharArray(), + keyPassword.toCharArray()); + + SSLContext sslContext = sslContextBuilder.build(); + + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( + sslContext, + SSLConnectionSocketFactory.getDefaultHostnameVerifier()); + + CloseableHttpClient httpClient = HttpClients.custom() + .setSSLSocketFactory(sslsf) + .build(); + + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); + factory.setReadTimeout(5000);// 单位为ms + factory.setConnectTimeout(5000);// 单位为ms + return factory; + } catch (Exception e) { + e.printStackTrace(); + } + } + + SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); + factory.setReadTimeout(5000);// 单位为ms + factory.setConnectTimeout(5000);// 单位为ms + return factory; + } + + @Bean(name = "authnAccountRestTemplate") + public RestTemplate authnAccountRestTemplate(ClientHttpRequestFactory requestFactory) { + return new RestTemplate(requestFactory); + } + +} diff --git a/gateway/src/main/java/com/supwisdom/institute/backend/gateway/authn/remote/web/client/AuthnAccountRemoteRestTemplate.java b/gateway/src/main/java/com/supwisdom/institute/backend/gateway/authn/remote/web/client/AuthnAccountRemoteRestTemplate.java new file mode 100644 index 0000000..65cf89f --- /dev/null +++ b/gateway/src/main/java/com/supwisdom/institute/backend/gateway/authn/remote/web/client/AuthnAccountRemoteRestTemplate.java @@ -0,0 +1,123 @@ +package com.supwisdom.institute.backend.gateway.authn.remote.web.client; + +import lombok.extern.slf4j.Slf4j; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import com.alibaba.fastjson.JSONObject; + +@Slf4j +@Component +public class AuthnAccountRemoteRestTemplate { + + @Autowired + private RestTemplate authnAccountRestTemplate; + + @Value(value = "${sw-backend-base-api.uri}/v1/authn") + private String url; + + private JSONObject defaultErrorJson(Throwable cause) { + JSONObject error = new JSONObject(); + + error.put("code", -1); + error.put("message", cause.getMessage()); + error.put("error", cause.getMessage()); + + return error; + } + + public JSONObject account(String username) { + + try { + final String path = "/{username}/account"; + final String url = this.url + StringUtils.replaceEach(path, new String[] {"{username}"}, new String[] {username}); + log.debug(url); + + return authnAccountRestTemplate.getForObject(this.url + path, JSONObject.class); + } catch (Exception e) { + e.printStackTrace(); + + return defaultErrorJson(e); + } + } + + public JSONObject roles(String username) { + + try { + final String path = "/{username}/roles"; + final String url = this.url + StringUtils.replaceEach(path, new String[] {"{username}"}, new String[] {username}); + log.debug(url); + + return authnAccountRestTemplate.getForObject(url, JSONObject.class); + } catch (Exception e) { + e.printStackTrace(); + + return defaultErrorJson(e); + } + } + + public JSONObject applications(String username, String applicationId) { + + try { + final String path = "/{username}/applications"; + final String url = this.url + StringUtils.replaceEach(path, new String[] {"{username}"}, new String[] {username}); + log.debug(url); + + return authnAccountRestTemplate.getForObject(this.url + path, JSONObject.class); + } catch (Exception e) { + e.printStackTrace(); + + return defaultErrorJson(e); + } + } + + public JSONObject menus(String username, String applicationId) { + + try { + final String path = "/{username}/menus"; + final String url = this.url + StringUtils.replaceEach(path, new String[] {"{username}"}, new String[] {username}); + log.debug(url); + + return authnAccountRestTemplate.getForObject(this.url + path, JSONObject.class); + } catch (Exception e) { + e.printStackTrace(); + + return defaultErrorJson(e); + } + } + + public JSONObject operations(String username, String applicationId) { + + try { + final String path = "/{username}/operations"; + final String url = this.url + StringUtils.replaceEach(path, new String[] {"{username}"}, new String[] {username}); + log.debug(url); + + return authnAccountRestTemplate.getForObject(this.url + path, JSONObject.class); + } catch (Exception e) { + e.printStackTrace(); + + return defaultErrorJson(e); + } + } + + public JSONObject resources(String username, String applicationId) { + + try { + final String path = "/{username}/resources"; + final String url = this.url + StringUtils.replaceEach(path, new String[] {"{username}"}, new String[] {username}); + log.debug(url); + + return authnAccountRestTemplate.getForObject(this.url + path, JSONObject.class); + } catch (Exception e) { + e.printStackTrace(); + + return defaultErrorJson(e); + } + } + +} diff --git a/gateway/src/main/java/com/supwisdom/institute/backend/gateway/authn/service/AuthnAccountService.java b/gateway/src/main/java/com/supwisdom/institute/backend/gateway/authn/service/AuthnAccountService.java new file mode 100644 index 0000000..beeb74a --- /dev/null +++ b/gateway/src/main/java/com/supwisdom/institute/backend/gateway/authn/service/AuthnAccountService.java @@ -0,0 +1,71 @@ +package com.supwisdom.institute.backend.gateway.authn.service; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson.JSONObject; +import com.supwisdom.institute.backend.gateway.authn.model.Account; +import com.supwisdom.institute.backend.gateway.authn.model.Permission; +import com.supwisdom.institute.backend.gateway.authn.model.Role; +import com.supwisdom.institute.backend.gateway.authn.remote.web.client.AuthnAccountRemoteRestTemplate; + +@Service +public class AuthnAccountService { + +// @Autowired +// private AuthnAccountRemoteFeignClient authnAccountRemote; + + @Autowired + private AuthnAccountRemoteRestTemplate authnAccountRemote; + + public Account account(String username) { + + JSONObject jsonObject = authnAccountRemote.account(username); + if (jsonObject == null) { + return null; + } + + if (jsonObject.getIntValue("code") == 0) { + JSONObject data = jsonObject.getJSONObject("data"); + + return data.toJavaObject(Account.class); + } + + return null; + } + + public List roles(String username) { + + JSONObject jsonObject = authnAccountRemote.roles(username); + if (jsonObject == null) { + return null; + } + + if (jsonObject.getIntValue("code") == 0) { + JSONObject data = jsonObject.getJSONObject("data"); + + return data.getJSONArray("roles").toJavaList(Role.class); + } + + return null; + } + + public List menus(String username, String applicationId) { + + JSONObject jsonObject = authnAccountRemote.menus(username, applicationId); + if (jsonObject == null) { + return null; + } + + if (jsonObject.getIntValue("code") == 0) { + JSONObject data = jsonObject.getJSONObject("data"); + + return data.getJSONArray("permissions").toJavaList(Permission.class); + } + + return null; + } + +} diff --git a/gateway/src/main/java/com/supwisdom/institute/backend/gateway/configuration/UserDetailsServiceConfig.java b/gateway/src/main/java/com/supwisdom/institute/backend/gateway/configuration/UserDetailsServiceConfig.java index cafbc17..6f8be84 100644 --- a/gateway/src/main/java/com/supwisdom/institute/backend/gateway/configuration/UserDetailsServiceConfig.java +++ b/gateway/src/main/java/com/supwisdom/institute/backend/gateway/configuration/UserDetailsServiceConfig.java @@ -12,20 +12,20 @@ import lombok.extern.slf4j.Slf4j; @Configuration public class UserDetailsServiceConfig { -// @Bean -// public MyUserDetailsService userDetailsService() throws Exception { -// MyUserDetailsService myUserDetailsService = new MyUserDetailsService(); -// log.debug("UserDetailsServiceConfig myUserDetailsService is {}", myUserDetailsService); -// -// return myUserDetailsService; -// } - @Bean - public InMemeryUserDetailsService userDetailsService() throws Exception { - InMemeryUserDetailsService inMemeryUserDetailsService = new InMemeryUserDetailsService(); - log.debug("UserDetailsServiceConfig inMemeryUserDetailsService is {}", inMemeryUserDetailsService); + public MyUserDetailsService userDetailsService() throws Exception { + MyUserDetailsService myUserDetailsService = new MyUserDetailsService(); + log.debug("UserDetailsServiceConfig myUserDetailsService is {}", myUserDetailsService); - return inMemeryUserDetailsService; + return myUserDetailsService; } +// @Bean +// public InMemeryUserDetailsService userDetailsService() throws Exception { +// InMemeryUserDetailsService inMemeryUserDetailsService = new InMemeryUserDetailsService(); +// log.debug("UserDetailsServiceConfig inMemeryUserDetailsService is {}", inMemeryUserDetailsService); +// +// return inMemeryUserDetailsService; +// } + } diff --git a/gateway/src/main/java/com/supwisdom/institute/backend/gateway/security/core/userdetails/MyUserDetailsService.java b/gateway/src/main/java/com/supwisdom/institute/backend/gateway/security/core/userdetails/MyUserDetailsService.java index e5bfec8..171f2cf 100644 --- a/gateway/src/main/java/com/supwisdom/institute/backend/gateway/security/core/userdetails/MyUserDetailsService.java +++ b/gateway/src/main/java/com/supwisdom/institute/backend/gateway/security/core/userdetails/MyUserDetailsService.java @@ -15,6 +15,10 @@ import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; +import com.supwisdom.institute.backend.gateway.authn.model.Account; +import com.supwisdom.institute.backend.gateway.authn.model.Role; +import com.supwisdom.institute.backend.gateway.authn.service.AuthnAccountService; + import reactor.core.publisher.Mono; import lombok.extern.slf4j.Slf4j; @@ -24,46 +28,16 @@ public class MyUserDetailsService implements UserDetailsService, ReactiveUserDet @Autowired PasswordEncoder passwordEncoder; -// @Autowired -// AccountService accountService; + @Autowired + AuthnAccountService authnAccountService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // TODO: log.debug("MyUserDetailsService.loadUserByUsername({})", username); -// Account account = accountService.loadByUsername(username); -// if (account == null) { -// throw new UsernameNotFoundException(String.format("%s not found", username)); -// } -// -// List authorities = new ArrayList(); -//// for (Role role : securityUser.getRoles()) { -//// authorities.add(new SimpleGrantedAuthority(role.getCode())); -//// } -// // FIXME: -// authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN")); -// authorities.add(new SimpleGrantedAuthority("administrator")); -// authorities.add(new SimpleGrantedAuthority("user")); -// -// Map attributes = new HashMap(); -// attributes.put("userId", account.getUser().getId()); -// attributes.put("userUid", account.getUser().getUid()); -// -// MyUser myUser = new MyUser( -// account.getAccountName(), -// account.getUser().getPassWord(), -// account.getActivation() && "Normal".equals(account.getState()) ? true : false, -// account.getAccountExpiryDate() == null || Calendar.getInstance().getTime().before(account.getAccountExpiryDate()) ? true : false, -// true, -// true, -// authorities, -// attributes); -// -// log.debug("myUser is {}", myUser); - - MyUser myUser = null; - + MyUser myUser = loadUser(username); + return myUser; } @@ -71,9 +45,37 @@ public class MyUserDetailsService implements UserDetailsService, ReactiveUserDet public Mono findByUsername(String username) { log.debug("MyUserDetailsService.findByUsername({})", username); - MyUser myUser = null; - + MyUser myUser = loadUser(username); + return Mono.just(myUser); } + + private MyUser loadUser(String username) { + + Account account = authnAccountService.account(username); + if (account == null) { + throw new UsernameNotFoundException(String.format("%s not found", username)); + } + + List roles = authnAccountService.roles(username); + + List authorities = new ArrayList(); + for (Role role : roles) { + authorities.add(new SimpleGrantedAuthority(role.getCode())); + } + + Map attributes = new HashMap(); + attributes.put("accountId", account.getId()); + attributes.put("accountName", account.getName()); + //attributes.put("accountMobile", account.getMobile()); + //attributes.put("accountEmail", account.getEmail()); + + MyUser myUser = new MyUser(account.getUsername(), passwordEncoder.encode(account.getPassword()), + account.getEnabled(), account.getAccountNonExpired(), account.getCredentialsNonExpired(), account.getAccountNonLocked(), + authorities, attributes); + log.debug("myUser is {}", myUser); + + return myUser; + } } diff --git a/gateway/src/main/resources/application-docker.yml b/gateway/src/main/resources/application-docker.yml index b5ea861..219f4f7 100644 --- a/gateway/src/main/resources/application-docker.yml +++ b/gateway/src/main/resources/application-docker.yml @@ -103,3 +103,15 @@ app.logout.url: ${APP_LOGOUT_URL:/cas/logout} #CAS服务地址 cas.server.host.url: ${CAS_SERVER_HOST_URL:https://cas-server/cas} + + +sw-backend-base-api: + uri: ${SW_BACKEND_BASE_API_URI:https://sw-backend-admin-sa} + client-auth: + enabled: ${SW_BACKEND_BASE_API_CLIENT_AUTH_ENABLED:true} + key-password: ${SW_BACKEND_BASE_API_CLIENT_AUTH_KEY_PASSWORD:} + key-store: ${SW_BACKEND_BASE_API_CLIENT_AUTH_KEYSTORE_FILE:file:/certs/common/common.keystore} + key-store-password: ${SW_BACKEND_BASE_API_CLIENT_AUTH_KEYSTORE_PASSWORD:} + trust-store: ${SW_BACKEND_BASE_API_CLIENT_AUTH_TRUSTSTORE_FILE:file:/certs/common/common.truststore} + trust-store-password: ${SW_BACKEND_BASE_API_CLIENT_AUTH_TRUSTSTORE_PASSWORD:} + \ No newline at end of file diff --git a/gateway/src/main/resources/application.yml b/gateway/src/main/resources/application.yml index 7e88467..c72cbc7 100644 --- a/gateway/src/main/resources/application.yml +++ b/gateway/src/main/resources/application.yml @@ -94,3 +94,7 @@ app.logout.url: /cas/logout #CAS服务地址 cas.server.host.url: https://cas.supwisdom.com/cas + + +sw-backend-base-api: + uri: http://localhost:8082