Introducing new features. closed #I4C55T

This commit is contained in:
jiojio 2021-09-27 18:04:54 +08:00
parent 584d72b0dc
commit 2fead0dce8
15 changed files with 46 additions and 97 deletions

View File

@ -16,11 +16,10 @@
package com.pig4cloud.pig.auth.config;
import com.pig4cloud.pig.auth.converter.CustomAccessTokenConverter;
import com.pig4cloud.pig.common.security.grant.ResourceOwnerPhoneTokenGranter;
import com.pig4cloud.pig.common.core.constant.CacheConstants;
import com.pig4cloud.pig.common.core.constant.SecurityConstants;
import com.pig4cloud.pig.common.security.component.PigWebResponseExceptionTranslator;
import com.pig4cloud.pig.common.security.grant.ResourceOwnerCustomeAppTokenGranter;
import com.pig4cloud.pig.common.security.service.PigClientDetailsService;
import com.pig4cloud.pig.common.security.service.PigUser;
import lombok.RequiredArgsConstructor;
@ -83,8 +82,7 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
.tokenEnhancer(tokenEnhancer()).userDetailsService(userDetailsService)
.authenticationManager(authenticationManager).reuseRefreshTokens(false)
.pathMapping("/oauth/confirm_access", "/token/confirm_access")
.exceptionTranslator(new PigWebResponseExceptionTranslator())
.accessTokenConverter(new CustomAccessTokenConverter(pigClientDetailsService()));
.exceptionTranslator(new PigWebResponseExceptionTranslator());
setTokenGranter(endpoints);
}
@ -92,10 +90,10 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
// 获取默认授权类型
TokenGranter tokenGranter = endpoints.getTokenGranter();
ArrayList<TokenGranter> tokenGranters = new ArrayList<>(Arrays.asList(tokenGranter));
ResourceOwnerPhoneTokenGranter resourceOwnerPhoneTokenGranter = new ResourceOwnerPhoneTokenGranter(
ResourceOwnerCustomeAppTokenGranter resourceOwnerCustomeAppTokenGranter = new ResourceOwnerCustomeAppTokenGranter(
authenticationManager, endpoints.getTokenServices(), endpoints.getClientDetailsService(),
endpoints.getOAuth2RequestFactory());
tokenGranters.add(resourceOwnerPhoneTokenGranter);
tokenGranters.add(resourceOwnerCustomeAppTokenGranter);
CompositeTokenGranter compositeTokenGranter = new CompositeTokenGranter(tokenGranters);
endpoints.tokenGranter(compositeTokenGranter);
}

View File

@ -16,7 +16,7 @@
package com.pig4cloud.pig.auth.config;
import com.pig4cloud.pig.common.security.grant.PhoneAuthenticationProvider;
import com.pig4cloud.pig.common.security.grant.CustomAppAuthenticationProvider;
import com.pig4cloud.pig.common.security.handler.FormAuthenticationFailureHandler;
import com.pig4cloud.pig.common.security.handler.SsoLogoutSuccessHandler;
import lombok.AllArgsConstructor;
@ -60,8 +60,8 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
/**
* 不要直接使用@Bean注入 会导致默认的提供者无法注入DaoAuthenticationProvider
*/
private PhoneAuthenticationProvider phoneAuthenticationProvider() {
PhoneAuthenticationProvider phoneAuthenticationProvider = new PhoneAuthenticationProvider();
private CustomAppAuthenticationProvider phoneAuthenticationProvider() {
CustomAppAuthenticationProvider phoneAuthenticationProvider = new CustomAppAuthenticationProvider();
phoneAuthenticationProvider.setUserDetailsService(userDetailsService);
return phoneAuthenticationProvider;
}

View File

@ -1,37 +0,0 @@
package com.pig4cloud.pig.auth.converter;
import com.pig4cloud.pig.common.core.constant.SecurityConstants;
import com.pig4cloud.pig.common.security.service.PigClientDetailsService;
import com.pig4cloud.pig.common.security.service.PigUser;
import lombok.RequiredArgsConstructor;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
import java.util.Map;
/**
* @author hccake
*/
@RequiredArgsConstructor
public class CustomAccessTokenConverter extends DefaultAccessTokenConverter {
final PigClientDetailsService pigClientDetailsService;
@Override
@SuppressWarnings("unchecked")
public Map<String, ?> convertAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
Map<String, Object> response = (Map<String, Object>) super.convertAccessToken(token, authentication);
ClientDetails clientDetails = pigClientDetailsService
.loadClientByClientId(authentication.getOAuth2Request().getClientId());
if (clientDetails != null && clientDetails.getScope().contains("read_data_scope")) {
PigUser principal = (PigUser) authentication.getPrincipal();
response.put(SecurityConstants.DETAILS_USER_DATA_SCOPE, principal.getUserDataScope());
}
return response;
}
}

View File

@ -60,7 +60,7 @@ public interface SecurityConstants {
/**
* 手机号登录
*/
String PHONE = "phone";
String APP = "app";
/**
* {bcrypt} 加密的特征码

View File

@ -1,6 +1,5 @@
package com.pig4cloud.pig.common.security.grant;
import cn.hutool.core.util.StrUtil;
import com.pig4cloud.pig.common.security.service.PigUserDetailsServiceImpl;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
@ -11,14 +10,13 @@ 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 org.springframework.security.core.userdetails.UsernameNotFoundException;
/**
* @author hzq
* @since 2021-09-14
*/
@Slf4j
public class PhoneAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
public class CustomAppAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
@Setter
private UserDetailsService userDetailsService;
@ -51,14 +49,8 @@ public class PhoneAuthenticationProvider extends AbstractUserDetailsAuthenticati
// 手机号
String phone = authentication.getName();
if (StrUtil.equals(phone, "17034642999")) {
throw new UsernameNotFoundException(phone);
}
String code = authentication.getCredentials().toString();
UserDetails userDetails = ((PigUserDetailsServiceImpl) userDetailsService).loadUserByPhone(phone);
PhoneAuthenticationToken token = new PhoneAuthenticationToken(userDetails);
CustomAppAuthenticationToken token = new CustomAppAuthenticationToken(userDetails);
token.setDetails(authentication.getDetails());
return token;
}
@ -71,7 +63,7 @@ public class PhoneAuthenticationProvider extends AbstractUserDetailsAuthenticati
@Override
public boolean supports(Class<?> authentication) {
return authentication.isAssignableFrom(PhoneAuthenticationToken.class);
return authentication.isAssignableFrom(CustomAppAuthenticationToken.class);
}
}

View File

@ -8,20 +8,20 @@ import org.springframework.security.core.userdetails.UserDetails;
* @author hzq
* @since 2021-09-14
*/
public class PhoneAuthenticationToken extends AbstractAuthenticationToken {
public class CustomAppAuthenticationToken extends AbstractAuthenticationToken {
private final Object principal;
// 验证码/密码
private String code;
public PhoneAuthenticationToken(String phone, String code) {
public CustomAppAuthenticationToken(String phone, String code) {
super(AuthorityUtils.NO_AUTHORITIES);
this.principal = phone;
this.code = code;
}
public PhoneAuthenticationToken(UserDetails sysUser) {
public CustomAppAuthenticationToken(UserDetails sysUser) {
super(sysUser.getAuthorities());
this.principal = sysUser;
super.setAuthenticated(true); // 设置认证成功 必须

View File

@ -20,19 +20,19 @@ import java.util.Map;
* @author hzq
* @since 2021-09-14
*/
public class ResourceOwnerPhoneTokenGranter extends AbstractTokenGranter {
public class ResourceOwnerCustomeAppTokenGranter extends AbstractTokenGranter {
private static final String GRANT_TYPE = "phone";
private static final String GRANT_TYPE = "app";
private final AuthenticationManager authenticationManager;
public ResourceOwnerPhoneTokenGranter(AuthenticationManager authenticationManager,
public ResourceOwnerCustomeAppTokenGranter(AuthenticationManager authenticationManager,
AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService,
OAuth2RequestFactory requestFactory) {
this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
}
protected ResourceOwnerPhoneTokenGranter(AuthenticationManager authenticationManager,
protected ResourceOwnerCustomeAppTokenGranter(AuthenticationManager authenticationManager,
AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService,
OAuth2RequestFactory requestFactory, String grantType) {
super(tokenServices, clientDetailsService, requestFactory, grantType);
@ -45,18 +45,18 @@ public class ResourceOwnerPhoneTokenGranter extends AbstractTokenGranter {
Map<String, String> parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters());
// 手机号
String phone = parameters.get("phone");
String mobile = parameters.get("mobile");
// 验证码/密码
String code = parameters.get("code");
if (StrUtil.isBlank(phone) || StrUtil.isBlank(code)) {
if (StrUtil.isBlank(mobile) || StrUtil.isBlank(code)) {
throw new InvalidGrantException("Bad credentials [ params must be has phone with code ]");
}
// Protect from downstream leaks of code
parameters.remove("code");
Authentication userAuth = new PhoneAuthenticationToken(phone, code);
Authentication userAuth = new CustomAppAuthenticationToken(mobile, code);
((AbstractAuthenticationToken) userAuth).setDetails(parameters);
try {
userAuth = authenticationManager.authenticate(userAuth);
@ -68,7 +68,7 @@ public class ResourceOwnerPhoneTokenGranter extends AbstractTokenGranter {
// If the phone/code are wrong the spec says we should send 400/invalid grant
if (userAuth == null || !userAuth.isAuthenticated()) {
throw new InvalidGrantException("Could not authenticate user: " + phone);
throw new InvalidGrantException("Could not authenticate user: " + mobile);
}
OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);

View File

@ -87,7 +87,7 @@ public class PigUserDetailsServiceImpl implements UserDetailsService {
* @return 用户信息
*/
public UserDetails loadUserByPhone(String phone) {
R<UserInfo> result = remoteUserService.infoByPhone(phone, SecurityConstants.FROM_IN);
R<UserInfo> result = remoteUserService.infoByMobile(phone, SecurityConstants.FROM_IN);
UserDetails userDetails = getUserDetails(result);
return userDetails;
}

View File

@ -70,8 +70,7 @@ public class ValidateCodeGatewayFilter extends AbstractGatewayFilterFactory<Obje
// 刷新token手机号登录也可以这里进行校验 直接向下执行
String grantType = request.getQueryParams().getFirst("grant_type");
if (StrUtil.equals(SecurityConstants.REFRESH_TOKEN, grantType)
|| StrUtil.equals(SecurityConstants.PHONE, grantType)) {
if (StrUtil.equals(SecurityConstants.REFRESH_TOKEN, grantType)) {
return chain.filter(exchange);
}

View File

@ -53,8 +53,8 @@ public interface RemoteUserService {
* @param from 调用标志
* @return R
*/
@GetMapping("/mobile/{phone}")
R<UserInfo> infoByPhone(@PathVariable("phone") String phone, @RequestHeader(SecurityConstants.FROM) String from);
@GetMapping("/app/info/{mobile}")
R<UserInfo> infoByMobile(@PathVariable("mobile") String mobile, @RequestHeader(SecurityConstants.FROM) String from);
/**
* 根据部门id查询对应的用户 id 集合

View File

@ -56,8 +56,8 @@ public class RemoteUserServiceFallbackImpl implements RemoteUserService {
* @return R
*/
@Override
public R<UserInfo> infoByPhone(String phone, String from) {
log.error("feign 查询用户信息失败手机号码:{}", phone, cause);
public R<UserInfo> infoByMobile(String mobile, String from) {
log.error("feign 查询用户信息失败手机号码:{}", mobile, cause);
return null;
}

View File

@ -2,7 +2,7 @@ package com.pig4cloud.pig.admin.controller;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.pig4cloud.pig.admin.api.entity.SysUser;
import com.pig4cloud.pig.admin.service.MobileService;
import com.pig4cloud.pig.admin.service.AppService;
import com.pig4cloud.pig.admin.service.SysUserService;
import com.pig4cloud.pig.common.core.util.R;
import com.pig4cloud.pig.common.security.annotation.Inner;
@ -19,18 +19,18 @@ import org.springframework.web.bind.annotation.RestController;
*/
@RestController
@AllArgsConstructor
@RequestMapping("/mobile")
@Api(value = "mobile", tags = "手机管理模块")
public class MobileController {
@RequestMapping("/app")
@Api(value = "app", tags = "手机管理模块")
public class AppController {
private final MobileService mobileService;
private final AppService appService;
private final SysUserService userService;
@Inner(value = false)
@GetMapping("/{mobile}")
public R sendSmsCode(@PathVariable String mobile) {
return mobileService.sendSmsCode(mobile);
return appService.sendSmsCode(mobile);
}
/**
@ -39,11 +39,11 @@ public class MobileController {
* @return 用户信息
*/
@Inner
@GetMapping("/{phone}")
public R infoByPhone(@PathVariable String phone) {
SysUser user = userService.getOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getPhone, phone));
@GetMapping("/info/{mobile}")
public R infoByMobile(@PathVariable String mobile) {
SysUser user = userService.getOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getPhone, mobile));
if (user == null) {
return R.failed(String.format("用户信息为空 %s", phone));
return R.failed(String.format("用户信息为空 %s", mobile));
}
return R.ok(userService.getUserInfo(user));
}

View File

@ -23,7 +23,7 @@ import com.pig4cloud.pig.common.core.util.R;
* @author lengleng
* @date 2018/11/14
*/
public interface MobileService {
public interface AppService {
/**
* 发送手机验证码

View File

@ -19,13 +19,11 @@ package com.pig4cloud.pig.admin.service;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.pig4cloud.pig.admin.api.entity.SysUser;
import com.pig4cloud.pig.admin.mapper.SysUserMapper;
import com.pig4cloud.pig.common.core.constant.CacheConstants;
import com.pig4cloud.pig.common.core.constant.SecurityConstants;
import com.pig4cloud.pig.common.core.constant.enums.LoginTypeEnum;
import com.pig4cloud.pig.common.core.util.R;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -44,7 +42,7 @@ import java.util.concurrent.TimeUnit;
@Slf4j
@Service
@AllArgsConstructor
public class MobileServiceImpl implements MobileService {
public class AppServiceImpl implements AppService {
private final RedisTemplate redisTemplate;
@ -65,8 +63,7 @@ public class MobileServiceImpl implements MobileService {
return R.ok(Boolean.FALSE, "手机号未注册");
}
Object codeObj = redisTemplate.opsForValue()
.get(CacheConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + StringPool.AT + mobile);
Object codeObj = redisTemplate.opsForValue().get(CacheConstants.DEFAULT_CODE_KEY + mobile);
if (codeObj != null) {
log.info("手机号验证码未过期:{}{}", mobile, codeObj);
@ -75,9 +72,8 @@ public class MobileServiceImpl implements MobileService {
String code = RandomUtil.randomNumbers(Integer.parseInt(SecurityConstants.CODE_SIZE));
log.debug("手机号生成验证码成功:{},{}", mobile, code);
redisTemplate.opsForValue().set(
CacheConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + StringPool.AT + mobile, code,
SecurityConstants.CODE_TIME, TimeUnit.SECONDS);
redisTemplate.opsForValue().set(CacheConstants.DEFAULT_CODE_KEY + mobile, code, SecurityConstants.CODE_TIME,
TimeUnit.SECONDS);
return R.ok(Boolean.TRUE, code);
}

View File

@ -30,6 +30,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
@ -68,9 +69,9 @@ public class SysRoleMenuServiceImpl extends ServiceImpl<SysRoleMenuMapper, SysRo
}).collect(Collectors.toList());
// 清空userinfo
cacheManager.getCache(CacheConstants.USER_DETAILS).clear();
Objects.requireNonNull(cacheManager.getCache(CacheConstants.USER_DETAILS)).clear();
// 清空全部的菜单缓存 fix #I4BM58
cacheManager.getCache(CacheConstants.MENU_DETAILS).clear();
Objects.requireNonNull(cacheManager.getCache(CacheConstants.MENU_DETAILS)).clear();
return this.saveBatch(roleMenuList);
}