增加短信登录 修改密码登录模式

master
bynt 2 years ago
parent 54da04ea1b
commit 55218a0baa

@ -0,0 +1,160 @@
package com.baiye.core.constant;
/**
* URL
*
* @author xuzhanfu
* @date 2019-10-10 17:46
**/
public class Oauth2Constant {
public static final String ALL = "/**";
public static final String OAUTH_ALL = "/oauth/**";
public static final String OAUTH_AUTHORIZE = "/oauth/authorize";
public static final String OAUTH_CHECK_TOKEN = "/oauth/check_token";
public static final String OAUTH_CONFIRM_ACCESS = "/oauth/confirm_access";
public static final String OAUTH_TOKEN = "/oauth/token";
public static final String OAUTH_TOKEN_KEY = "/oauth/token_key";
public static final String OAUTH_ERROR = "/oauth/error";
public static final String OAUTH_MOBILE = "/oauth/mobile";
/**
*
*/
public static final String DEFAULT_PARAMETER_NAME_MOBILE = "mobile";
/**
*
*/
public static final String DEFAULT_PARAMETER_NAME_SOCIAL = "social";
/**
* key
*/
public static final String VALIDATE_CODE_KEY = "key";
/**
* code
*/
public static final String VALIDATE_CODE_CODE = "code";
/**
* key
*/
public static final String GRANT_TYPE = "grant_type";
/**
*
*/
public static final String LOGIN_TYPE = "login_type";
/**
*
*/
public static final String REFRESH_TOKEN = "refresh_token";
/**
*
*/
public static final String AUTHORIZATION_CODE = "authorization_code";
/**
*
*/
public static final String CLIENT_CREDENTIALS = "client_credentials";
/**
*
*/
public static final String PASSWORD = "password";
/**
*
*/
public static final String IMPLICIT = "implicit";
public static final String SIGN_KEY = "MATE";
public static final String CAPTCHA_KEY = "mate.captcha.";
public static final String SMS_CODE_KEY = "mate.sms.code.";
public static final String CAPTCHA_HEADER_KEY = "key";
public static final String CAPTCHA_HEADER_CODE = "code";
public static final int LOGIN_USERNAME_TYPE = 1;
public static final int LOGIN_MOBILE_TYPE = 2;
public static final String HEADER_TOKEN = "Mate-Auth";
/**
* client
*/
public static final String CLIENT_TABLE = "mate_sys_client";
public static final String CAPTCHA_ERROR = "验证码不正确!";
public static final String SUPER_ADMIN = "admin";
/**
*
*/
public static final String CLIENT_BASE = "select client_id, CONCAT('{noop}',client_secret) as client_secret, resource_ids, scope, " +
"authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity," +
"refresh_token_validity, additional_information, autoapprove from " + CLIENT_TABLE;
public static final String FIND_CLIENT_DETAIL_SQL = CLIENT_BASE + " order by client_id";
public static final String SELECT_CLIENT_DETAIL_SQL = CLIENT_BASE + " where client_id = ?";
/**
*
*/
public static final String FROM = "from";
/**
*
*/
public static final String FROM_IN = "Y";
/**
*
*/
public static final String MATE_PERMISSION_PREFIX = "mate.permission.";
/**
* ID
*/
public static final String MATE_USER_ID = "userId";
/**
*
*/
public static final String MATE_USER_NAME = "userName";
/**
*
*/
public static final String MATE_AVATAR = "avatar";
/**
* ID
*/
public static final String MATE_ROLE_ID = "roleId";
/**
*
*/
public static final String MATE_TYPE = "type";
/**
* ID
*/
public static final String MATE_TENANT_ID = "tenantId";
}

@ -91,4 +91,8 @@ public final class SecurityConstants {
public static final CharSequence REFRESH_TOKEN = "refresh_token";
public static final String SMS_GRANT_TYPE = "sms_code";
public static final String SIGN_KEY = "BY_CDP";
}

@ -70,6 +70,9 @@ public class GlobalExceptionHandler {
return buildResponseEntity(ApiError.error(e.getStatus(),e.getMessage()));
}
/**
* EntityExist
*/

@ -0,0 +1,22 @@
package com.baiye.service;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
/**
*
* @author pangu
*/
public interface CdpUserDetailsService extends UserDetailsService {
/**
*
* @param mobile
* @return UserDetails
* @throws UsernameNotFoundException
*/
UserDetails loadUserByMobile(String mobile) throws UsernameNotFoundException;
}

@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import com.baiye.component.LoginUser;
import com.baiye.config.LoginProperties;
import com.baiye.core.constant.CacheKey;
import com.baiye.core.constant.DefaultNumberConstants;
import com.baiye.core.constant.SecurityConstants;
import com.baiye.dto.UserSmallDto;
import com.baiye.feign.IRemoteUserService;
@ -15,7 +16,6 @@ import org.springframework.cache.CacheManager;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@ -25,15 +25,14 @@ import java.util.List;
import java.util.Set;
/**
*
* @description
* @author Enzo
* @description
* @date 2020-08-05 17:35
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {
public class UserDetailsServiceImpl implements CdpUserDetailsService {
/**
@ -41,20 +40,21 @@ public class UserDetailsServiceImpl implements UserDetailsService {
*/
private final IRemoteUserService remoteUserService;
/**
*
*/
private final CacheManager cacheManager;
/**
*
*/
private final LoginProperties loginProperties;
/**
*
*/
private final CacheManager cacheManager;
/**
*
*
* @param enableCache
*/
public void setEnableCache(Boolean enableCache) {
@ -63,6 +63,7 @@ public class UserDetailsServiceImpl implements UserDetailsService {
/**
*
*
* @param username
* @return
* @throws UsernameNotFoundException
@ -88,6 +89,7 @@ public class UserDetailsServiceImpl implements UserDetailsService {
/**
* UserDetails
*
* @param user
* @return
*/
@ -95,30 +97,43 @@ public class UserDetailsServiceImpl implements UserDetailsService {
if (user == null) {
throw new UsernameNotFoundException("用户不存在");
}
// SysUser sysUser = result.getBody();
Set<String> dbAuthsSet = new HashSet<>();
if (CollUtil.isNotEmpty(user.getRoleNames())) {
user.getRoleNames().forEach(role -> {
dbAuthsSet.add(SecurityConstants.ROLE + role);
});
// TODO: 2020/8/12 远程查询部门数据权限
//......
user.getRoleNames().forEach(role -> dbAuthsSet.add(SecurityConstants.ROLE + role));
}
if (user.getIsAdmin()){
if (Boolean.TRUE.equals(user.getIsAdmin())) {
dbAuthsSet.add(SecurityConstants.ADMIN);
}else if (CollUtil.isNotEmpty(user.getPermissions())){
} else if (CollUtil.isNotEmpty(user.getPermissions())) {
dbAuthsSet.addAll(user.getPermissions());
}
// 封装为Collection<? extends GrantedAuthority>
String[] authArray = dbAuthsSet.stream().filter(StringUtils::isNotBlank).toArray(String[]::new);
// 不能传入空字符串
List<GrantedAuthority> authorityList = null;
if (CollUtil.isNotEmpty(dbAuthsSet)){
if (CollUtil.isNotEmpty(dbAuthsSet)) {
authorityList = AuthorityUtils.createAuthorityList(authArray);
}
return new LoginUser(user.getId(), user.getUsername(), user.getPassword(), user.getEnabled(),
true, true, true, authorityList, new ArrayList<>());
}
@Override
public UserDetails loadUserByMobile(String mobile) throws UsernameNotFoundException {
Cache cache = this.cacheManager.getCache(CacheKey.USER_DETAILS);
if (cache != null && cache.get(mobile) != null) {
// 缓存中存在,直接从缓存中获取
return (LoginUser) cache.get(mobile).get();
}
// 缓存不存在则调用feign获取用户信息
UserSmallDto result = this.remoteUserService.getUserDetailsByMobile(mobile, SecurityConstants.FROM_IN);
UserDetails userDetails = this.getUserDetails(result);
// 放入缓存
if (Boolean.TRUE.equals(loginProperties.getCacheEnable())) {
assert cache != null;
cache.put(mobile, userDetails);
}
return userDetails;
}
}

@ -60,6 +60,12 @@
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
<version>2.0.23</version>
</dependency>
</dependencies>
<!-- 配置插件 -->

@ -1,72 +1,97 @@
package com.baiye.auth.config;
import com.baiye.auth.translator.CustomWebRespExceptionTranslator;
import com.baiye.auth.feign.IRemoteMemberService;
import com.baiye.auth.sms.granter.SmsCodeTokenGranter;
import com.baiye.auth.service.IOnlineUserService;
import com.baiye.auth.translator.CustomWebRespExceptionTranslator;
import com.baiye.core.constant.CacheKey;
import com.baiye.core.constant.SecurityConstants;
import com.baiye.component.LoginUser;
import com.baiye.core.util.RedisUtils;
import com.baiye.service.CustomClientDetailsService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
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.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
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.redis.RedisTokenStore;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
import javax.sql.DataSource;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
*
* @description
* @author Enzo
* @description
* @date 2020-08-03 16:14
*/
@Configuration
@EnableAuthorizationServer
@RequiredArgsConstructor
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
@Value("${cdp.auth.isSingleLogin:false}")
private boolean isSingleLogin;
/**
* redis
*/
private final RedisConnectionFactory redisConnectionFactory;
/**
*
*/
private final AuthenticationManager authenticationManager;
private final IRemoteMemberService remoteMemberService;
/**
* 线
* clientService
*/
private IOnlineUserService onlineUserService;
private final ClientDetailsService clientService;
/**
* 使sql
* UserDetailsService,
*/
private final DataSource dataSource;
private final UserDetailsService userDetailsService;
/**
* redis
* 线
*/
private final RedisConnectionFactory redisConnectionFactory;
private IOnlineUserService onlineUserService;
/**
* UserDetailsService,
* 使sql
*/
private final UserDetailsService userDetailsService;
private final DataSource dataSource;
private final RedisUtils redisUtils;
@Autowired
@ -75,8 +100,6 @@ public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer.allowFormAuthenticationForClients().checkTokenAccess("permitAll()");
@ -99,10 +122,22 @@ public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
@Override
@SuppressWarnings("unchecked")
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
DefaultTokenServices tokenServices = createDefaultTokenServices();
// token增强链
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
// 把jwt增强与额外信息增强加入到增强链
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), jwtAccessTokenConverter()));
tokenServices.setTokenEnhancer(tokenEnhancerChain);
// 配置tokenServices参数
addUserDetailsService(tokenServices);
endpoints
.tokenGranter(tokenGranter(endpoints, tokenServices))
.tokenServices(tokenServices)
.accessTokenConverter(jwtAccessTokenConverter())
// 配置请求方式
.allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST)
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
// 配置token的存储位置
.tokenStore(redisTokenStore())
// 自定义生成token
@ -118,36 +153,46 @@ public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
.exceptionTranslator(new CustomWebRespExceptionTranslator());
}
private DefaultTokenServices createDefaultTokenServices() {
DefaultTokenServices tokenServices = new SingleLoginTokenServices(isSingleLogin, onlineUserService);
tokenServices.setTokenStore(redisTokenStore());
// 支持刷新Token
tokenServices.setSupportRefreshToken(Boolean.TRUE);
tokenServices.setReuseRefreshToken(Boolean.FALSE);
tokenServices.setClientDetailsService(clientService);
addUserDetailsService(tokenServices);
return tokenServices;
}
/**
* token
*
* @return
*/
@Bean
public TokenEnhancer tokenEnhancer() {
return (accessToken, authentication) -> {
if (accessToken instanceof DefaultOAuth2AccessToken){
LoginUser loginUser = (LoginUser) authentication.getUserAuthentication().getPrincipal();
// TODO: 2020/8/5 在token中后续添加权限信息
/*
*
*/
String authorities = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(","));
Map<String, Object> additionalInformation = new LinkedHashMap<String, Object>(4);
additionalInformation.put(SecurityConstants.DETAILS_USER_ID,loginUser.getUserId());
additionalInformation.put(SecurityConstants.DETAILS_USERNAME, loginUser.getUsername());
additionalInformation.put(SecurityConstants.DATA_SCOPES, loginUser.getDataScopes());
additionalInformation.put(SecurityConstants.AUTHORITIES_KEY,authorities);
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInformation);
onlineUserService.saveOnlineUser(accessToken);
if (accessToken instanceof DefaultOAuth2AccessToken) {
SingleLoginTokenServices.setUser(authentication, (DefaultOAuth2AccessToken) accessToken);
// onlineUserService.saveOnlineUser(accessToken);
}
return accessToken;
};
}
private void addUserDetailsService(DefaultTokenServices tokenServices) {
if (userDetailsService != null) {
PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
provider.setPreAuthenticatedUserDetailsService(new UserDetailsByNameServiceWrapper<>(userDetailsService));
tokenServices.setAuthenticationManager(new ProviderManager(Collections.singletonList(provider)));
}
}
/**
* redisredis
*
* @return TokenStore
*/
@Bean
@ -158,4 +203,32 @@ public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
return redisTokenStore;
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setSigningKey(SecurityConstants.SIGN_KEY);
return jwtAccessTokenConverter;
}
/**
*
*
*
* @param endpoints AuthorizationServerEndpointsConfigurer
* @return TokenGranter
*/
private TokenGranter tokenGranter(final AuthorizationServerEndpointsConfigurer endpoints, DefaultTokenServices tokenServices) {
List<TokenGranter> granters = new ArrayList<>(Collections.singletonList(endpoints.getTokenGranter()));
// 短信验证码模式
granters.add(new SmsCodeTokenGranter(authenticationManager, tokenServices, endpoints.getClientDetailsService(),
endpoints.getOAuth2RequestFactory(), redisUtils, remoteMemberService));
// 增加密码模式
granters.add(new ResourceOwnerPasswordTokenGranter(authenticationManager, tokenServices, endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory()));
return new CompositeTokenGranter(granters);
}
}

@ -0,0 +1,156 @@
package com.baiye.auth.config;
import cn.hutool.json.JSONUtil;
import com.baiye.auth.service.IOnlineUserService;
import com.baiye.component.LoginUser;
import com.baiye.core.constant.SecurityConstants;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.common.*;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* DefaultTokenServices
*
* @author pangu
* @date 2021-2-10
* @since 2.3.8
*/
public class SingleLoginTokenServices extends DefaultTokenServices {
private TokenStore tokenStore;
private TokenEnhancer accessTokenEnhancer;
/**
*
*/
private final boolean isSingleLogin;
/**
*
*/
private final IOnlineUserService onlineUserService;
public SingleLoginTokenServices(boolean isSingleLogin, IOnlineUserService onlineUserService) {
this.isSingleLogin = isSingleLogin;
this.onlineUserService = onlineUserService;
}
@Override
@Transactional(rollbackFor = Exception.class)
public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {
OAuth2AccessToken existingAccessToken = tokenStore.getAccessToken(authentication);
OAuth2RefreshToken refreshToken = null;
if (existingAccessToken != null) {
if (isSingleLogin) {
if (existingAccessToken.getRefreshToken() != null) {
tokenStore.removeRefreshToken(existingAccessToken.getRefreshToken());
}
tokenStore.removeAccessToken(existingAccessToken);
} else if (existingAccessToken.isExpired()) {
if (existingAccessToken.getRefreshToken() != null) {
refreshToken = existingAccessToken.getRefreshToken();
// The token store could remove the refresh token when the
// access token is removed, but we want to
// be sure...
tokenStore.removeRefreshToken(refreshToken);
}
tokenStore.removeAccessToken(existingAccessToken);
} else {
// Re-store the access token in case the authentication has changed
tokenStore.storeAccessToken(existingAccessToken, authentication);
return existingAccessToken;
}
}
// Only create a new refresh token if there wasn't an existing one
// associated with an expired access token.
// Clients might be holding existing refresh tokens, so we re-use it in
// the case that the old access token
// expired.
if (refreshToken == null) {
refreshToken = createRefreshToken(authentication);
}
// But the refresh token itself might need to be re-issued if it has
// expired.
else if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
ExpiringOAuth2RefreshToken expiring = (ExpiringOAuth2RefreshToken) refreshToken;
if (System.currentTimeMillis() > expiring.getExpiration().getTime()) {
refreshToken = createRefreshToken(authentication);
}
}
OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
tokenStore.storeAccessToken(accessToken, authentication);
// In case it was modified
refreshToken = accessToken.getRefreshToken();
if (refreshToken != null) {
tokenStore.storeRefreshToken(refreshToken, authentication);
}
setUser(authentication, (DefaultOAuth2AccessToken) accessToken);
onlineUserService.saveOnlineUser(accessToken);
return accessToken;
}
static void setUser(OAuth2Authentication authentication, DefaultOAuth2AccessToken accessToken) {
LoginUser user = (LoginUser) authentication.getUserAuthentication().getPrincipal();
String authorities = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(","));
Map<String, Object> additionalInformation = new LinkedHashMap<>(4);
additionalInformation.put(SecurityConstants.DETAILS_USER_ID, user.getUserId());
additionalInformation.put(SecurityConstants.DETAILS_USERNAME, user.getUsername());
additionalInformation.put(SecurityConstants.DATA_SCOPES, user.getDataScopes());
additionalInformation.put(SecurityConstants.AUTHORITIES_KEY, authorities);
accessToken.setAdditionalInformation(additionalInformation);
}
private OAuth2RefreshToken createRefreshToken(OAuth2Authentication authentication) {
if (!isSupportRefreshToken(authentication.getOAuth2Request())) {
return null;
}
int validitySeconds = getRefreshTokenValiditySeconds(authentication.getOAuth2Request());
String value = UUID.randomUUID().toString();
if (validitySeconds > 0) {
return new DefaultExpiringOAuth2RefreshToken(value, new Date(System.currentTimeMillis()
+ (validitySeconds * 1000L)));
}
return new DefaultOAuth2RefreshToken(value);
}
private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) {
DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(UUID.randomUUID().toString());
int validitySeconds = getAccessTokenValiditySeconds(authentication.getOAuth2Request());
if (validitySeconds > 0) {
token.setExpiration(new Date(System.currentTimeMillis() + (validitySeconds * 1000L)));
}
token.setRefreshToken(refreshToken);
token.setScope(authentication.getOAuth2Request().getScope());
return accessTokenEnhancer != null ? accessTokenEnhancer.enhance(token, authentication) : token;
}
@Override
public void setTokenStore(TokenStore tokenStore) {
this.tokenStore = tokenStore;
super.setTokenStore(tokenStore);
}
@Override
public void setTokenEnhancer(TokenEnhancer accessTokenEnhancer) {
this.accessTokenEnhancer = accessTokenEnhancer;
super.setTokenEnhancer(accessTokenEnhancer);
}
}

@ -0,0 +1,44 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baiye.auth.config.properties;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* @author Zheng Jie
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "sms")
public class SmsProperties {
@ApiModelProperty(value = "accessKeyId")
private String accessKeyId;
@ApiModelProperty(value = "accessKeySecret")
private String accessKeySecret;
@ApiModelProperty(value = "signName")
private String signName;
@ApiModelProperty(value = "templateCode")
private String templateCode;
}

@ -0,0 +1,58 @@
package com.baiye.auth.controller;
import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.nacos.common.utils.Md5Utils;
import com.baiye.core.annotation.Log;
import com.baiye.core.base.api.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.*;
import java.security.Principal;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Oauth2
*
* @author pangu
* @link https://segmentfault.com/a/1190000020317220?utm_source=tag-newest
*/
@RestController
@RequestMapping("/oauth")
@AllArgsConstructor
@Api(value = "Oauth2管理")
public class OauthController {
private final TokenEndpoint tokenEndpoint;
@Log(value = "用户登录", exception = "用户登录请求异常")
@PostMapping("/token")
@ApiOperation(value = "用户登录Post")
@ApiImplicitParams({
@ApiImplicitParam(value = "grant_type", required = true, name = "授权类型"),
@ApiImplicitParam(value = "username", required = true, name = "用户名"),
@ApiImplicitParam(value = "password", required = true, name = "密码"),
@ApiImplicitParam(value = "scope", required = true, name = "使用范围"),
})
public Result<Map<String, Object>> postAccessToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
OAuth2AccessToken body = tokenEndpoint.postAccessToken(principal, parameters).getBody();
DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) body;
Map<String, Object> data = new LinkedHashMap<>(token.getAdditionalInformation());
data.put("accessToken", token.getValue());
if (token.getRefreshToken() != null) {
data.put("refreshToken", token.getRefreshToken().getValue());
}
return Result.data(data);
}
}

@ -0,0 +1,31 @@
package com.baiye.auth.controller;
import com.baiye.auth.service.SmsService;
import com.baiye.core.base.api.Result;
import io.swagger.annotations.Api;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
/**
* @author Enzo
* @date : 2023/3/15
*/
@RestController
@RequestMapping("/sms")
@Api(value = "阿里云短信服务")
@RequiredArgsConstructor
public class SmsController {
private final SmsService smsService;
@GetMapping("/getCode")
@ResponseBody
public Result<String> sendSMS(@RequestParam String mobile){
if (StringUtils.isBlank(mobile)) {
return Result.fail("发送短信失败");
}
return smsService.sendSms(mobile) ? Result.success() : Result.fail();
}
}

@ -0,0 +1,30 @@
package com.baiye.auth.feign;
import com.baiye.core.constant.SecurityConstants;
import com.baiye.core.constant.ServiceNameConstants;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author Enzo
* @description feign
* @date 2020-08-12 16:50
*/
@FeignClient(contextId = "remoteMemberService", value = ServiceNameConstants.BACKSTAGE_SERVER)
public interface IRemoteMemberService {
/**
*
*
* @param username
* @param from
* @return
*/
@GetMapping(value = "/member/createOrUpdate")
Boolean createOrUpdate(@RequestParam("username") String username, @RequestHeader(SecurityConstants.FROM) String from);
}

@ -0,0 +1,15 @@
package com.baiye.auth.service;
/**
* @author Enzo
* @date : 2023/3/15
*/
public interface SmsService {
/**
*
* @param mobile
* @return
*/
Boolean sendSms(String mobile);
}

@ -0,0 +1,64 @@
package com.baiye.auth.service.impl;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.baiye.auth.config.properties.SmsProperties;
import com.baiye.auth.service.SmsService;
import com.baiye.core.constant.DefaultNumberConstants;
import com.baiye.core.constant.Oauth2Constant;
import com.baiye.core.util.RedisUtils;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
/**
* @author Enzo
* @date : 2023/3/15
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class SmsServiceImpl implements SmsService {
private final RedisUtils redisUtils;
private final SmsProperties smsProperties;
@Override
@SneakyThrows
public Boolean sendSms(String mobile) {
Config config = new Config()
.setAccessKeyId(smsProperties.getAccessKeyId())
.setAccessKeySecret(smsProperties.getAccessKeySecret());
config.endpoint = "dysmsapi.aliyuncs.com";
String code = RandomUtil.randomNumbers(DefaultNumberConstants.SIX_NUMBER);
Client client = new Client(config);
SendSmsRequest sendSmsRequest = new SendSmsRequest();
sendSmsRequest
.setSignName(smsProperties.getSignName())
.setPhoneNumbers(mobile)
.setTemplateCode(smsProperties.getTemplateCode());
HashMap<String, Object> param = new HashMap<>(DefaultNumberConstants.EIGHT_NUMBER);
param.put("code", code);
sendSmsRequest.setTemplateParam(JSON.toJSONString(param));
RuntimeOptions runtime = new RuntimeOptions();
SendSmsResponse response = client.sendSmsWithOptions(sendSmsRequest, runtime);
if ("OK".equals(response.body.code)) {
redisUtils.set(Oauth2Constant.SMS_CODE_KEY.concat(mobile),
code, DefaultNumberConstants.FIVE_NUMBER, TimeUnit.MINUTES);
return Boolean.TRUE;
}
return Boolean.FALSE;
}
}

@ -0,0 +1,80 @@
package com.baiye.auth.sms;
import com.baiye.core.constant.Oauth2Constant;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.Assert;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.swing.text.html.FormSubmitEvent;
import java.util.Objects;
/**
*
*
* @author pangu
*/
public class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
/**
*
*/
private String mobileParameter = Oauth2Constant.DEFAULT_PARAMETER_NAME_MOBILE;
private boolean postOnly = true;
public SmsCodeAuthenticationFilter() {
super(new AntPathRequestMatcher(Oauth2Constant.OAUTH_MOBILE, "POST"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (postOnly && !FormSubmitEvent.MethodType.POST.name().equals(request.getMethod())) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
// 获取请求中的参数值
String mobile = obtainMobile(request);
if (Objects.isNull(mobile)) {
mobile = "";
}
mobile = mobile.trim();
SmsCodeAuthenticationToken authRequest = new SmsCodeAuthenticationToken(mobile);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
/**
*
*/
protected String obtainMobile(HttpServletRequest request) {
return request.getParameter(mobileParameter);
}
protected void setDetails(HttpServletRequest request, SmsCodeAuthenticationToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}
public void setMobileParameter(String mobileParameter) {
Assert.hasText(mobileParameter, "Mobile parameter must not be empty or null");
this.mobileParameter = mobileParameter;
}
public void setPostOnly(boolean postOnly) {
this.postOnly = postOnly;
}
public final String getMobileParameter() {
return mobileParameter;
}
}

@ -0,0 +1,49 @@
package com.baiye.auth.sms;
import com.baiye.service.CdpUserDetailsService;
import lombok.AllArgsConstructor;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import java.util.Objects;
/**
*
*
* @author pangu
*/
@AllArgsConstructor
public class SmsCodeAuthenticationProvider implements AuthenticationProvider {
private final CdpUserDetailsService userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication;
/**
* {@link UserDetailsService}
*/
UserDetails user = userDetailsService.loadUserByMobile((String) authenticationToken.getPrincipal());
if (Objects.isNull(user)) {
throw new InternalAuthenticationServiceException("手机号或验证码错误");
}
SmsCodeAuthenticationToken authenticationResult = new SmsCodeAuthenticationToken(user, user.getAuthorities());
authenticationResult.setDetails(authenticationToken.getDetails());
return authenticationResult;
}
@Override
public boolean supports(Class<?> authentication) {
return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
}
}

@ -0,0 +1,38 @@
package com.baiye.auth.sms;
import com.baiye.service.CdpUserDetailsService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;
/**
*
*
* @author pangu
*/
@Component
@RequiredArgsConstructor
public class SmsCodeAuthenticationSecurityConfig
extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
private final CdpUserDetailsService userDetailsService;
@Override
public void configure(HttpSecurity http) {
// 过滤器
SmsCodeAuthenticationFilter smsCodeAuthenticationFilter = new SmsCodeAuthenticationFilter();
smsCodeAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
// 获取验证码提供者
SmsCodeAuthenticationProvider smsCodeAuthenticationProvider = new SmsCodeAuthenticationProvider(userDetailsService);
// 将短信验证码校验器注册到 HttpSecurity 并将短信验证码过滤器添加在 UsernamePasswordAuthenticationFilter 之前
http.authenticationProvider(smsCodeAuthenticationProvider)
.addFilterAfter(smsCodeAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
}

@ -0,0 +1,58 @@
package com.baiye.auth.sms;
import lombok.SneakyThrows;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;
/**
*
*
* @author pangu
* @since 2020-7-21
*/
public class SmsCodeAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = -3629824093049247125L;
private final Object principal;
public SmsCodeAuthenticationToken(String mobile) {
super(null);
this.principal = mobile;
setAuthenticated(false);
}
public SmsCodeAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
super.setAuthenticated(true);
}
@Override
public Object getCredentials() {
return this.principal;
}
@Override
public Object getPrincipal() {
return this.principal;
}
@Override
@SneakyThrows
public void setAuthenticated(boolean isAuthenticated) {
if (isAuthenticated) {
throw new IllegalArgumentException(
"Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
}
super.setAuthenticated(false);
}
@Override
public void eraseCredentials() {
super.eraseCredentials();
}
}

@ -0,0 +1,99 @@
package com.baiye.auth.sms.granter;
import cn.hutool.core.text.CharSequenceUtil;
import com.baiye.auth.feign.IRemoteMemberService;
import com.baiye.auth.sms.SmsCodeAuthenticationToken;
import com.baiye.core.constant.Oauth2Constant;
import com.baiye.core.constant.SecurityConstants;
import com.baiye.core.util.RedisUtils;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AccountStatusException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.common.exceptions.UserDeniedAuthorizationException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* TokenGranter
*
* @author pangu
* @since 2020-7-21
*/
public class SmsCodeTokenGranter extends AbstractTokenGranter {
private final AuthenticationManager authenticationManager;
private final IRemoteMemberService remoteMemberService;
private RedisUtils redisUtils;
public SmsCodeTokenGranter(AuthenticationManager authenticationManager,
AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService,
OAuth2RequestFactory requestFactory, RedisUtils redisUtils,IRemoteMemberService remoteMemberService) {
this(authenticationManager, tokenServices, clientDetailsService, requestFactory, SecurityConstants.SMS_GRANT_TYPE, remoteMemberService);
this.redisUtils = redisUtils;
}
protected SmsCodeTokenGranter(AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices,
ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, String grantType, IRemoteMemberService remoteMemberService) {
super(tokenServices, clientDetailsService, requestFactory, grantType);
this.authenticationManager = authenticationManager;
this.remoteMemberService = remoteMemberService;
}
@Override
protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
Map<String, String> parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters());
String mobile = parameters.get("mobile");
String code = parameters.get("code");
if (CharSequenceUtil.isBlank(code)) {
throw new UserDeniedAuthorizationException("请输入验证码!");
}
String codeFromRedis;
// 从Redis里读取存储的验证码信息
try {
codeFromRedis = redisUtils.get(Oauth2Constant.SMS_CODE_KEY + mobile).toString();
} catch (Exception e) {
throw new UserDeniedAuthorizationException("验证码不存在!");
}
if (codeFromRedis == null) {
throw new UserDeniedAuthorizationException("验证码已过期!");
}
// 比较输入的验证码是否正确
if (!CharSequenceUtil.equalsIgnoreCase(code, codeFromRedis)) {
throw new UserDeniedAuthorizationException("验证码不正确!");
}
redisUtils.del(Oauth2Constant.SMS_CODE_KEY + mobile);
// 创建或修改账号
remoteMemberService.createOrUpdate(mobile, SecurityConstants.FROM_IN);
Authentication userAuth = new SmsCodeAuthenticationToken(mobile);
((AbstractAuthenticationToken) userAuth).setDetails(parameters);
try {
userAuth = authenticationManager.authenticate(userAuth);
} catch (AccountStatusException | BadCredentialsException ase) {
//covers expired, locked, disabled cases (mentioned in section 5.2, draft 31)
throw new InvalidGrantException(ase.getMessage());
}
// If the username/password are wrong the spec says we should send 400/invalid grant
if (userAuth == null || !userAuth.isAuthenticated()) {
throw new InvalidGrantException("Could not authenticate user: " + mobile);
}
OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
return new OAuth2Authentication(storedOAuth2Request, userAuth);
}
}

@ -23,7 +23,6 @@ public class CustomWebRespExceptionTranslator implements WebResponseExceptionTra
@Override
public ResponseEntity<?> translate(Exception e) {
ResponseEntity.BodyBuilder status = ResponseEntity.status(HttpStatus.UNAUTHORIZED);
String message = "认证失败";
log.error(message, e);
if (e instanceof UnsupportedGrantTypeException) {

@ -54,7 +54,8 @@ public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object> {
}
// 如果是刷新token的请求直接放行
String grandType = request.getQueryParams().getFirst("grant_type");
if (CharSequenceUtil.equals(SecurityConstants.REFRESH_TOKEN,grandType)){
if (CharSequenceUtil.equals(SecurityConstants.REFRESH_TOKEN,grandType)
|| CharSequenceUtil.equals(SecurityConstants.SMS_GRANT_TYPE,grandType)){
return chain.filter(exchange);
}
// 主要是对swagger认证进行放行

@ -12,43 +12,6 @@ spring:
driver-class-name: com.mysql.jdbc.Driver
username: ${MYSQL_USER:root}
password: ${MYSQL_PASSWORD:y7z7noq2}
cloud:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true # admin-service ADMIN-SERVICE /admin-service/** -> 微服务 (ADMIN-SERVICE) 自动转发,忽略大小写
routes:
- id: backstage-server
uri: lb://backstage-server # 负载均衡转发到哪个目的地
predicates:
- Path=/sys/**
filters:
- StripPrefix=1
- id: cdp-wechat-api
uri: lb://cdp-wechat-api
predicates:
- Path=/api-wechat/**
filters:
- StripPrefix=1
- id: cdp-entrance-api
uri: lb://cdp-entrance-api
predicates:
- Path=/api-file/**
filters:
- StripPrefix=1
- id: dy-tool-member-api
uri: lb://dy-tool-member-api
predicates:
- Path=/api-tiktok/**
filters:
- StripPrefix=1
- id: cdp-tool-xhs-api
uri: lb://cdp-tool-xhs-api
predicates:
- Path=/api-xhs/**
filters:
- StripPrefix=1
nacos:
server-addr: 127.0.0.1:8848
# server-addr: 101.35.109.129

@ -12,37 +12,7 @@ spring:
driver-class-name: com.mysql.jdbc.Driver
username: ${MYSQL_USER:root}
password: ${MYSQL_PASSWORD:baiye@RDS2023.}
cloud:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true # admin-service ADMIN-SERVICE /admin-service/** -> 微服务 (ADMIN-SERVICE) 自动转发,忽略大小写
routes:
- id: backstage-server
uri: lb://backstage-server # 负载均衡转发到哪个目的地
predicates:
- Path=/sys/**
filters:
- StripPrefix=1
- id: cdp-wechat-api
uri: lb://cdp-wechat-api
predicates:
- Path=/api-wechat/**
filters:
- StripPrefix=1
- id: cdp-entrance-api
uri: lb://cdp-entrance-api
predicates:
- Path=/api-file/**
filters:
- StripPrefix=1
- id: cdp-tool-xhs-api
uri: lb://cdp-tool-xhs-api
predicates:
- Path=/api-xhs/**
filters:
- StripPrefix=1
nacos:
server-addr: 172.16.69.134:8848
# server-addr: 101.35.109.129:8848

@ -1,9 +1,46 @@
spring:
application:
name: @artifactId@
profiles:
active: dev
application:
name: @artifactId@
cloud:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true # admin-service ADMIN-SERVICE /admin-service/** -> 微服务 (ADMIN-SERVICE) 自动转发,忽略大小写
routes:
- id: backstage-server
uri: lb://backstage-server # 负载均衡转发到哪个目的地
predicates:
- Path=/sys/**
filters:
- StripPrefix=1
- id: cdp-wechat-api
uri: lb://cdp-wechat-api
predicates:
- Path=/api-wechat/**
filters:
- StripPrefix=1
- id: cdp-entrance-api
uri: lb://cdp-entrance-api
predicates:
- Path=/api-file/**
filters:
- StripPrefix=1
- id: cdp-tool-xhs-api
uri: lb://cdp-tool-xhs-api
predicates:
- Path=/api-xhs/**
filters:
- StripPrefix=1
- id: auth-server
uri: lb://auth-server
predicates:
- Path=/cdp-uaa/**
filters:
- StripPrefix=1
security:
decode:
private-key: MIICXAIBAAKBgQDYws76QjIeL8KDfr9sAFF14ccKy+iF9j71JO/5brB969Gjjf4gr9JM7OYWr2T51lWa+4sCt7/zn7XlIo9vmOD2mqohC0D4gSkixBlDAlp511OQQbZlb4fEw8W1/IltcpTolhjYh9dQoilmUThZB6bhims/0P6auSN6qvtIVS0tPwIDAQABAoGAREyNvxkghZZy6dAELNmk0UoE14gMijle+QtcefHAtsyZT7mr+0yrLQXwMfGuFXLNonnkAUU4vGD0hXBwVa+MIlMWnPCb9fxuj45dXQjycoD2kCY6l+rhuEJqu/ruHAWBnp30vGtLf2+EoRKFAAoGiwILiHa3cDr/k+n3JwRXn9ECQQD9+rN7Z2gvakWYgwwJIV5ebKd/MVainYrp0biYNlqi8ELgMlFtFahMLnqDpy+vhnRdcnha2672E3tc7GjKPzfFAkEA2nxNUHb5hCU26eudBcZ9lxaMw3o+6F3aGDLv9SVwvHtQWXN0CZM72UO7/E2dfgeelUyNakk3WqG56WFmoLDdMwJABeX2mR0TrFY5e4s/kk62FFdNpISO0IP8H+YA9Xf9rt8Jjo9cmL3yBKLnsXsGfnsO5MStyt5jN8/IA6Zx4JCLSQJAMVYmY0gqegOpTdNNpvM2gvqtmKqvL+uZhyNhejsVJQq3jyt6BXuA5UPdXFDugnoX/mDGAj08SbQBdkjvUtP9bwJBAIPaqbt+qHxXcBqpUaM3zDp1hQHH2xxpYSJsJWF99RB5srRL4AsA4N6Hy63zo6335k1IAPaH6uk9vobyhiCC/E0=

@ -0,0 +1,83 @@
package com.baiye;
import com.baiye.core.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Date;
import java.util.Objects;
/**
* @author Zheng Jie
* @date 2019-03-25
*/
@Setter
@Getter
@TableName("tb_member")
public class Member extends BaseEntity implements Serializable {
private static final long serialVersionUID = -3797115638759597781L;
@NotNull(groups = {Update.class})
@TableId(value = "member_id", type = IdType.AUTO)
@ApiModelProperty(value = "ID", hidden = true)
private Long id;
@NotBlank
@ApiModelProperty(value = "用户名称")
private String username;
@Email
@NotBlank
@ApiModelProperty(value = "邮箱")
private String email;
@NotBlank
@ApiModelProperty(value = "电话号码")
private String phone;
@ApiModelProperty(value = "用户性别")
private String gender;
@ApiModelProperty(value = "头像真实名称", hidden = true)
private String avatarName;
@ApiModelProperty(value = "头像存储的路径", hidden = true)
private String avatarPath;
@ApiModelProperty(value = "密码")
private String password;
@NotNull
@ApiModelProperty(value = "是否启用")
private Boolean enabled;
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Member user = (Member) o;
return Objects.equals(id, user.id) &&
Objects.equals(username, user.username);
}
@Override
public int hashCode() {
return Objects.hash(id, username);
}
}

@ -0,0 +1,81 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baiye.dto;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baiye.core.base.BaseDTO;
import com.baiye.core.excel.BoolCustomConverter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.util.Date;
import java.util.Set;
/**
*
* @author Enzo
* @date 2022-05-14
*/
@Getter
@Setter
@ExcelIgnoreUnannotated
public class MemberDto extends BaseDTO implements Serializable {
private static final long serialVersionUID = 967234921171721967L;
private Long id;
private Set<RoleSmallDto> roles;
private Set<JobSmallDto> jobs;
private DeptSmallDto dept;
private Long deptId;
@ExcelProperty("用户名")
private String username;
@ExcelProperty("昵称")
private String nickName;
@ExcelProperty("邮箱")
private String email;
@ExcelProperty("手机号")
private String phone;
@ExcelProperty("性别")
private String gender;
private String avatarName;
private String avatarPath;
@JsonIgnore
private String password;
@ExcelProperty(value = "是否启用",converter = BoolCustomConverter.class)
private Boolean enabled;
@ExcelProperty(value = "是否为管理员",converter = BoolCustomConverter.class)
@JsonIgnore
private Boolean isAdmin = false;
private Date pwdResetTime;
}

@ -9,18 +9,32 @@ import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
/**
*
* @description feign
* @author Enzo
* @description feign
* @date 2020-08-12 16:50
*/
@FeignClient(contextId = "remoteUserService", value = ServiceNameConstants.BACKSTAGE_SERVER)
public interface IRemoteUserService {
/**
*
*
*
* @param username
* @param from
* @return
*/
@GetMapping(value = "/inner/username")
UserSmallDto getUserDetails(@RequestParam("username") String username, @RequestHeader(SecurityConstants.FROM) String from);
/**
*
*
* @param mobile
* @param from
* @return
*/
@GetMapping(value = "/inner/mobile")
UserSmallDto getUserDetailsByMobile(@RequestParam("mobile") String mobile, @RequestHeader(SecurityConstants.FROM) String from);
}

@ -0,0 +1,31 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baiye.mapstruct;
import com.baiye.Member;
import com.baiye.core.base.BaseMapStruct;
import com.baiye.dto.MemberDto;
import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;
/**
* @author Zheng Jie
* @date 2018-11-23
*/
@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface MemberMapStruct extends BaseMapStruct<MemberDto, Member> {
}

@ -0,0 +1,44 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baiye.query;
import com.baiye.annotation.Query;
import com.baiye.annotation.type.SelectType;
import lombok.Data;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.List;
/**
* @author Zheng Jie
* @date 2018-11-23
*/
@Data
public class MemberQueryCriteria implements Serializable {
private static final long serialVersionUID = -8942145971476050045L;
@Query(blurry = {"email", "username", "nickName"})
private String blurry;
@Query
private Boolean enabled;
@Query(type = SelectType.BETWEEN)
private List<Timestamp> createTime;
}

@ -0,0 +1,79 @@
package com.baiye.controller;
import com.baiye.Member;
import com.baiye.User;
import com.baiye.annotation.Inner;
import com.baiye.core.page.PageResult;
import com.baiye.dto.UserDto;
import com.baiye.dto.UserSmallDto;
import com.baiye.query.MemberQueryCriteria;
import com.baiye.query.UserQueryCriteria;
import com.baiye.service.IMemberService;
import com.baiye.service.IUserService;
import com.baiye.util.SecurityUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.Map;
/**
* @author Enzo
* @date 2023-3-16
*/
@Api(tags = "系统: 会员管理")
@Slf4j
@RestController
@RequestMapping("/member")
@RequiredArgsConstructor
public class MemberController {
private final IMemberService memberService;
@ApiOperation("通过用户id查询用户姓名")
@GetMapping(value = "/id")
public ResponseEntity<String> queryByUserId(@RequestParam Long id) {
return ResponseEntity.ok(this.memberService.getById(id).getUsername());
}
@ApiOperation("查询用户")
@GetMapping
@PreAuthorize("@el.check('member:list')")
public ResponseEntity<PageResult> query(MemberQueryCriteria queryCriteria, Pageable pageable) {
return new ResponseEntity<>(this.memberService.queryAll(queryCriteria, pageable), HttpStatus.OK);
}
@ApiOperation("修改用户")
@PutMapping
@PreAuthorize("@el.check('user:edit')")
public ResponseEntity<Void> update(@Validated(Member.Update.class) @RequestBody Member resources) {
this.memberService.updateMember(resources);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@ApiOperation("修改头像")
@PostMapping(value = "/updateAvatar")
public ResponseEntity<Map<String, String>> updateAvatar(@RequestParam MultipartFile avatar) {
return new ResponseEntity<>(this.memberService.updateAvatar(avatar), HttpStatus.OK);
}
@Inner
@ApiOperation("通过用户名查询用户")
@GetMapping(value = "/createOrUpdate")
public ResponseEntity<Boolean> getUserDetails(@RequestParam String mobile){
return ResponseEntity.ok(this.memberService.createOrUpdate(mobile));
}
}

@ -2,6 +2,7 @@ package com.baiye.controller;
import com.baiye.annotation.Inner;
import com.baiye.dto.UserSmallDto;
import com.baiye.service.IMemberService;
import com.baiye.service.IUserService;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
@ -23,10 +24,21 @@ import org.springframework.web.bind.annotation.RestController;
public class UserDetailsController {
private final IUserService userService;
private final IMemberService memberService;
@Inner
@ApiOperation("通过用户名查询用户")
@GetMapping(value = "/username")
public ResponseEntity<UserSmallDto> getUserDetails(@RequestParam String username){
return ResponseEntity.ok(this.userService.getUserDetails(username));
}
@Inner
@ApiOperation("通过用户名查询用户")
@GetMapping(value = "/mobile")
public ResponseEntity<UserSmallDto> getUserDetailsByMobile(@RequestParam String mobile){
return ResponseEntity.ok(this.memberService.getUserDetailsByMobile(mobile));
}
}

@ -0,0 +1,53 @@
package com.baiye.mapper;
import com.baiye.Member;
import com.baiye.User;
import com.baiye.dto.UserSmallDto;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import java.util.List;
/**
* @author Enzo
* @date : 2023/3/16
*/
public interface MemberMapper extends BaseMapper<Member> {
/**
*
* @param wrapper
* @return
*/
List<Member> queryAll(QueryWrapper<Member> wrapper);
/**
*
* @param wrapper
* @param page
* @return
*/
Page<Member> queryAllWithPage(QueryWrapper<Member> wrapper, Page<Member> page);
/**
* id
* @param id
* @return
*/
Member getById(Long id);
/**
*
* @param currentUsername
* @return
*/
Member queryByUsername(String currentUsername);
/**
*
* @param mobile
* @return
*/
UserSmallDto getUserDetails(String mobile);
}

@ -0,0 +1,54 @@
package com.baiye.service;
import com.baiye.Member;
import com.baiye.User;
import com.baiye.core.page.PageResult;
import com.baiye.dto.UserSmallDto;
import com.baiye.query.MemberQueryCriteria;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.data.domain.Pageable;
import org.springframework.web.multipart.MultipartFile;
import java.util.Map;
/**
* @author Enzo
* @date : 2023/3/16
*/
public interface IMemberService extends IService<Member> {
/**
*
* @param queryCriteria
* @param pageable
* @return
*/
PageResult queryAll(MemberQueryCriteria queryCriteria, Pageable pageable);
/**
*
* @param resources
*/
void updateMember(Member resources);
/**
*
* @param avatar
* @return
*/
Map<String,String> updateAvatar(MultipartFile avatar);
/**
*
* @param mobile
* @return
*/
UserSmallDto getUserDetailsByMobile(String mobile);
/**
*
* @param mobile
* @return
*/
Boolean createOrUpdate(String mobile);
}

@ -0,0 +1,159 @@
package com.baiye.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baiye.Member;
import com.baiye.core.base.api.ResultCode;
import com.baiye.core.constant.CacheKey;
import com.baiye.core.page.PageResult;
import com.baiye.core.util.RedisUtils;
import com.baiye.dto.UserSmallDto;
import com.baiye.exception.global.BadRequestException;
import com.baiye.exception.global.UpdateFailException;
import com.baiye.feign.IRemoteAuthService;
import com.baiye.mapper.MemberMapper;
import com.baiye.mapstruct.MemberMapStruct;
import com.baiye.properties.FileProperties;
import com.baiye.query.MemberQueryCriteria;
import com.baiye.service.IMemberService;
import com.baiye.util.FileUtil;
import com.baiye.util.PageUtils;
import com.baiye.util.QueryHelpUtils;
import com.baiye.util.SecurityUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.ImmutableMap;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.constraints.NotBlank;
import java.io.File;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
/**
* @author Enzo
* @date : 2023/3/16
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> implements IMemberService {
private final RedisUtils redisUtils;
private final MemberMapper memberMapper;
private final FileProperties properties;
private final MemberMapStruct memberMapStruct;
private final IRemoteAuthService remoteAuthService;
@Override
public PageResult queryAll(MemberQueryCriteria queryCriteria, Pageable pageable) {
QueryWrapper<Member> wrapper = null;
if (BeanUtil.isNotEmpty(queryCriteria)) {
wrapper = QueryHelpUtils.getWrapper(queryCriteria, Member.class);
}
Page<Member> page = PageUtils.startPageAndSort(pageable);
Page<Member> memberPage = this.memberMapper.queryAllWithPage(wrapper, page);
return PageResult.success(memberPage.getTotal(), memberPage.getPages(),
this.memberMapStruct.toDto(memberPage.getRecords()));
}
@Override
public void updateMember(Member resources) {
// 如果用户被禁用,则清除用户登陆的信息
if (Boolean.FALSE.equals(resources.getEnabled())) {
try {
this.remoteAuthService.delete(Collections.singleton(resources.getId()));
} catch (Exception e) {
throw new BadRequestException(ResultCode.FAILURE.getMsg());
}
}
// 更新用户信息
boolean result = this.updateById(resources);
if (!result) {
// 更新失败,全部回滚
log.error("更新失败:{}", resources);
throw new UpdateFailException("更新失败,请联系管理员");
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public Map<String, String> updateAvatar(MultipartFile avatar) {
// 文件大小验证
FileUtil.checkSize(properties.getAvatarMaxSize(), avatar.getSize());
// 验证文件上传的格式
String image = "gif jpg png jpeg";
String fileType = FileUtil.getExtensionName(avatar.getOriginalFilename());
if (fileType != null && !image.contains(fileType)) {
throw new BadRequestException("文件格式错误!, 仅支持 " + image + " 格式");
}
Member member = memberMapper.queryByUsername(SecurityUtils.getCurrentUsername());
String oldPath = member.getAvatarPath();
File file = FileUtil.upload(avatar, properties.getPath().getAvatar());
member.setAvatarPath(Objects.requireNonNull(file).getPath());
member.setAvatarName(file.getName());
memberMapper.updateById(member);
if (CharSequenceUtil.isNotBlank(oldPath)) {
FileUtil.del(oldPath);
}
@NotBlank String username = member.getUsername();
this.delCaches(member.getId(), username);
return ImmutableMap.of("avatar", file.getName());
}
/**
*
*
* @param mobile
* @return
*/
@Override
@Cacheable(key = "'username:' + #p0")
public UserSmallDto getUserDetailsByMobile(String mobile) {
return this.memberMapper.getUserDetails(mobile);
}
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean createOrUpdate(String mobile) {
Member member = memberMapper.queryByUsername(mobile);
if (ObjectUtil.isNull(member)) {
member = new Member();
member.setId(IdUtil.getSnowflake().nextId());
member.setEnabled(Boolean.TRUE);
member.setPhone(mobile);
member.setUsername(mobile);
return this.save(member);
}
// 清除缓存
this.delCaches(member.getId(), member.getUsername());
return updateById(member);
}
/**
*
*
* @param id
* @param username
*/
private void delCaches(Long id, String username) {
this.redisUtils.del(CacheKey.USER_ID + id);
this.redisUtils.del(CacheKey.USER_NAME + username);
}
}

@ -4,7 +4,6 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.baiye.*;
import com.baiye.core.base.api.Result;
import com.baiye.core.base.api.ResultCode;
import com.baiye.core.constant.CacheKey;
import com.baiye.core.constant.EncryptionConstants;
@ -17,9 +16,8 @@ import com.baiye.dto.UserDto;
import com.baiye.dto.UserSmallDto;
import com.baiye.exception.global.*;
import com.baiye.feign.IRemoteAuthService;
import com.baiye.feign.IRemoteWechatService;
import com.baiye.mapper.UserMapper;
import com.baiye.mapper.UserJobMapper;
import com.baiye.mapper.UserMapper;
import com.baiye.mapper.UserRoleMapper;
import com.baiye.mapstruct.UserMapStruct;
import com.baiye.properties.FileProperties;
@ -39,7 +37,6 @@ import com.google.common.collect.Maps;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheConfig;
@ -50,7 +47,6 @@ import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
@ -86,14 +82,8 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IU
private final IRemoteAuthService remoteAuthService;
private final IRemoteWechatService remoteWechatService;
/**
* restTemplate访,RemoteTokenServices
*/
private final RestTemplate lbRestTemplate;
/**
*

@ -0,0 +1,70 @@
package com.baiye.util;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.List;
/**
* @author Enzo
* @date : 2023/2/16
*/
public class D {
static int num = 0;
public static void main(String[] args) {
// 序号1
int[] ints = {1, 3, 4};
String text = "今天,{}请吃饭{}吃饭,花了{}元,在本店消费排行{}名";
List<String> permute = permute(2, text, ints);
System.out.println(permute);
}
//存放最终答案的java容器
static List<String> ans = new ArrayList<>();
//全排列的方法
public static List<String> permute(int index, String text, int[] nums) {
//我们用来存放是否访问过的数组(避免重复使用某一元素)
boolean[] isVisted = new boolean[nums.length];
//回溯法的核心,这是一个递归的调用
dfs(index, text, nums, isVisted, new ArrayList<>());
//返回答案
return ans;
}
//核心算法
public static void dfs(int index, String text, int[] nums, boolean[] isVisited, List<Integer> path) {
//如果我们的路径也就是我们用来存放我们一步步加入元素的容器的尺寸和num数组的长度是一样的这说明我们找到了一个全排列所以我们把它放入最终的答案数组
if (path.size() == nums.length) {
List<Integer> integers = Lists.newArrayList(path);
integers.add(0, index);
String format = CharSequenceUtil.format(text, integers.toArray());
ans.add(format);
}
//我们对于从下标0到数组num长度减1的数进行遍历
for (int i = 0; i < nums.length; i++) {
//如果没有被访问,即被加入到路径容器中,就进行下面的操作
if (!isVisited[i]) {
//变成访问过的元素
isVisited[i] = true;
//加入到路径容器中
path.add(nums[i]);
//递归进行深度优先搜索
dfs(index, text, nums, isVisited, path);
//回溯的两步,去掉路径容器的最后的值,因为最后被添加的最先被回溯到
path.remove(path.size() - 1);
//第二步,因为回溯,所以这个元素要被设置回未访问的
isVisited[i] = false;
num++;
}
}
}
}

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.baiye.mapper.MemberMapper">
<resultMap id="baseUserMap" type="com.baiye.Member">
<id property="id" column="id"/>
<result property="avatarName" column="avatar_name"/>
<result property="avatarPath" column="avatar_path"/>
<result property="email" column="email"/>
<result property="gender" column="gender"/>
<result property="enabled" column="enabled"/>
<result property="password" column="password"/>
<result property="phone" column="phone"/>
<result property="username" column="username"/>
<result property="updateTime" column="update_time"/>
<result property="updateBy" column="update_by"/>
<result property="createTime" column="create_time"/>
<result property="createBy" column="create_by"/>
</resultMap>
<resultMap id="userDetailsMap" type="com.baiye.dto.UserSmallDto">
<id property="id" column="user_id"/>
<result property="username" column="username"/>
<result property="isAdmin" column="is_admin"/>
<result property="password" column="password"/>
<result property="enabled" column="enabled"/>
<collection property="permissions" column="permissions" ofType="java.lang.String">
<constructor>
<arg column="permissions"/>
</constructor>
</collection>
<collection property="roleNames" column="role_name" ofType="java.lang.String">
<constructor>
<arg column="role_name"/>
</constructor>
</collection>
</resultMap>
<sql id="baseUserSql">
${property}.member_id as id,
${property}.username,
${property}.password,
${property}.gender,
${property}.phone,
${property}.email,
${property}.avatar_name,
${property}.avatar_path,
${property}.password,
${property}.enabled,
${property}.create_by,
${property}.update_by,
${property}.create_time,
${property}.update_time
</sql>
<sql id="selectAllSql">
<include refid="baseUserSql">
<property name="property" value="sys_user"/>
</include>
FROM
tb_member
</sql>
<select id="queryAll" resultMap="baseUserMap">
select
<include refid="selectAllSql"/>
<if test="ew != null and ew.sqlSegment != ''">
and ${ew.sqlSegment}
</if>
</select>
<select id="queryAllWithPage" resultMap="baseUserMap">
select
<include refid="selectAllSql"/>
<if test="ew != null and ew.sqlSegment != ''">
and ${ew.sqlSegment}
</if>
</select>
<select id="getById" resultMap="baseUserMap">
select
<include refid="selectAllSql"/>
and sys_user.user_id = #{id}
</select>
<select id="queryByUsername" resultMap="baseUserMap">
select
<include refid="selectAllSql"/>
where tb_member.username = #{username}
</select>
<select id="getUserDetails" resultMap="userDetailsMap">
select me.user_id,
me.username,
me.password,
me.enabled
from tb_member me
where me.username = #{username};
</select>
</mapper>
Loading…
Cancel
Save