精简登陆授权流程,去除oauth相关的表,让人更容易读懂登陆授权

master
LGH 6 years ago
parent b229a4579c
commit ad8197d0f2

@ -4261,31 +4261,6 @@ insert into `tz_notice`(`id`,`shop_id`,`title`,`content`,`status`,`is_top`,`pub
(2,1,'超大容量折叠包,再也不担心旅游购物买爆','<p><span style=\"color: #222222; font-family: Consolas, \'Lucida Console\', \'Courier New\', monospace; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;\"><img style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"http://img-test.gz-yami.com/2019/04/febc23ad9cab40a3b7a9557df244b948.jpg\" alt=\"\" width=\"750\" height=\"450\" /></span></p>\n<p>&nbsp;</p>\n<p style=\"text-align: justify;\"><span style=\"color: #222222; font-family: Consolas, \'Lucida Console\', \'Courier New\', monospace; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;\">出国旅游,购物时很容易不小心就放飞自我,买一大堆东西,发现装不下了。这时,我就会从包里拿出严选折叠手提袋,优雅地解决&ldquo;爆买&rdquo;后无处安放的尴尬。</span></p>\n<p style=\"text-align: justify;\"><span style=\"color: #222222; font-family: Consolas, \'Lucida Console\', \'Courier New\', monospace; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;\">这个手提袋容量巨大双层防水面料但非常轻收纳起来只有手掌厚度和大小放在包里一点不占空间。真的超能装打开后最多能装25L抵半个行李箱了。袋子一侧能直接套入拉杆稳稳地放在箱子上拖起来毫不费力。我每次长途旅行必备它平时拿去买菜、健身房也很好用。</span></p>',1,1,'2019-04-22 15:54:55','2019-04-27 15:24:39'), (2,1,'超大容量折叠包,再也不担心旅游购物买爆','<p><span style=\"color: #222222; font-family: Consolas, \'Lucida Console\', \'Courier New\', monospace; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;\"><img style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"http://img-test.gz-yami.com/2019/04/febc23ad9cab40a3b7a9557df244b948.jpg\" alt=\"\" width=\"750\" height=\"450\" /></span></p>\n<p>&nbsp;</p>\n<p style=\"text-align: justify;\"><span style=\"color: #222222; font-family: Consolas, \'Lucida Console\', \'Courier New\', monospace; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;\">出国旅游,购物时很容易不小心就放飞自我,买一大堆东西,发现装不下了。这时,我就会从包里拿出严选折叠手提袋,优雅地解决&ldquo;爆买&rdquo;后无处安放的尴尬。</span></p>\n<p style=\"text-align: justify;\"><span style=\"color: #222222; font-family: Consolas, \'Lucida Console\', \'Courier New\', monospace; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;\">这个手提袋容量巨大双层防水面料但非常轻收纳起来只有手掌厚度和大小放在包里一点不占空间。真的超能装打开后最多能装25L抵半个行李箱了。袋子一侧能直接套入拉杆稳稳地放在箱子上拖起来毫不费力。我每次长途旅行必备它平时拿去买菜、健身房也很好用。</span></p>',1,1,'2019-04-22 15:54:55','2019-04-27 15:24:39'),
(3,1,'同是纯棉,为什么它睡起来如此舒服','<p style=\"text-align: justify;\"><span style=\"font-size: 20px;\"><img style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"http://img-test.gz-yami.com/2019/04/b837e346051a4c51a5d0d22e137187fe.jpg\" alt=\"\" width=\"670\" height=\"480\" /></span></p>\n<p style=\"text-align: justify;\">&nbsp;</p>\n<p style=\"text-align: justify;\"><span style=\"font-size: 20px;\"><span style=\"color: #222222; font-family: Consolas, \'Lucida Console\', \'Courier New\', monospace; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;\">说到床品,我一直很想要那种五星级酒店的面料,但每次都搞不懂那些纺织名词,稀里糊涂就买了,结果往往是不好睡。</span><br /></span></p>\n<p style=\"text-align: justify;\"><span style=\"font-size: 16px;\"><span style=\"color: #222222; font-family: Consolas, \'Lucida Console\', \'Courier New\', monospace; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;\">后来查了一下只有贡缎才具有这种光滑细腻的质感但织法工艺难度高一套动辄六七百。同事推荐了严选这款四件套是用60支的优质长绒棉每平方英寸400根线织成的非常细密柔软。</span></span></p>\n<p style=\"text-align: justify;\"><span style=\"font-size: 16px;\"><span style=\"color: #222222; font-family: Consolas, \'Lucida Console\', \'Courier New\', monospace; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;\">第一天睡觉的时候我惊呆了,同样是纯棉床品,为什么它睡起来如此舒服,竟然有着丝绸一样的顺滑触感。而且厚薄适中,透气性也不错,一年四季都能用,非常推荐。</span></span></p>\n<p>&nbsp;</p>',1,1,'2019-04-22 16:28:18','2019-04-27 15:25:00'); (3,1,'同是纯棉,为什么它睡起来如此舒服','<p style=\"text-align: justify;\"><span style=\"font-size: 20px;\"><img style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"http://img-test.gz-yami.com/2019/04/b837e346051a4c51a5d0d22e137187fe.jpg\" alt=\"\" width=\"670\" height=\"480\" /></span></p>\n<p style=\"text-align: justify;\">&nbsp;</p>\n<p style=\"text-align: justify;\"><span style=\"font-size: 20px;\"><span style=\"color: #222222; font-family: Consolas, \'Lucida Console\', \'Courier New\', monospace; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;\">说到床品,我一直很想要那种五星级酒店的面料,但每次都搞不懂那些纺织名词,稀里糊涂就买了,结果往往是不好睡。</span><br /></span></p>\n<p style=\"text-align: justify;\"><span style=\"font-size: 16px;\"><span style=\"color: #222222; font-family: Consolas, \'Lucida Console\', \'Courier New\', monospace; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;\">后来查了一下只有贡缎才具有这种光滑细腻的质感但织法工艺难度高一套动辄六七百。同事推荐了严选这款四件套是用60支的优质长绒棉每平方英寸400根线织成的非常细密柔软。</span></span></p>\n<p style=\"text-align: justify;\"><span style=\"font-size: 16px;\"><span style=\"color: #222222; font-family: Consolas, \'Lucida Console\', \'Courier New\', monospace; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;\">第一天睡觉的时候我惊呆了,同样是纯棉床品,为什么它睡起来如此舒服,竟然有着丝绸一样的顺滑触感。而且厚薄适中,透气性也不错,一年四季都能用,非常推荐。</span></span></p>\n<p>&nbsp;</p>',1,1,'2019-04-22 16:28:18','2019-04-27 15:25:00');
/*Table structure for table `tz_oauth_client_details` */
DROP TABLE IF EXISTS `tz_oauth_client_details`;
CREATE TABLE `tz_oauth_client_details` (
`client_id` varchar(32) CHARACTER SET utf8mb4 NOT NULL,
`client_secret` varchar(256) CHARACTER SET utf8mb4 DEFAULT NULL,
`resource_ids` varchar(256) CHARACTER SET utf8mb4 DEFAULT NULL,
`scope` varchar(256) CHARACTER SET utf8mb4 DEFAULT NULL,
`authorized_grant_types` varchar(256) CHARACTER SET utf8mb4 DEFAULT NULL,
`web_server_redirect_uri` varchar(256) CHARACTER SET utf8mb4 DEFAULT NULL,
`authorities` varchar(256) CHARACTER SET utf8mb4 DEFAULT NULL,
`access_token_validity` int(11) DEFAULT NULL,
`refresh_token_validity` int(11) DEFAULT NULL,
`additional_information` varchar(4096) CHARACTER SET utf8mb4 DEFAULT NULL,
`autoapprove` varchar(256) CHARACTER SET utf8mb4 DEFAULT NULL,
PRIMARY KEY (`client_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='终端信息表';
/*Data for the table `tz_oauth_client_details` */
insert into `tz_oauth_client_details`(`client_id`,`client_secret`,`resource_ids`,`scope`,`authorized_grant_types`,`web_server_redirect_uri`,`authorities`,`access_token_validity`,`refresh_token_validity`,`additional_information`,`autoapprove`) values
('admin','admin',NULL,'','',NULL,NULL,NULL,NULL,NULL,'true'),
('mini_app','mini_app',NULL,'','',NULL,NULL,NULL,NULL,NULL,'true'),
('weixin_mp','weixin_mp',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
/*Table structure for table `tz_order` */ /*Table structure for table `tz_order` */

@ -1,98 +0,0 @@
/*
* Copyright (c) 2018-2999 广 All rights reserved.
*
* https://www.gz-yami.com/
*
*
*
*
*/
package com.yami.shop.admin.security;
import cn.hutool.core.util.StrUtil;
import com.yami.shop.common.util.RedisUtil;
import com.yami.shop.security.constants.SecurityConstants;
import com.yami.shop.security.enums.App;
import com.yami.shop.security.exception.BadCredentialsExceptionBase;
import com.yami.shop.security.exception.ImageCodeNotMatchExceptionBase;
import com.yami.shop.security.exception.UsernameNotFoundExceptionBase;
import com.yami.shop.security.exception.BaseYamiAuth2Exception;
import com.yami.shop.security.provider.AbstractUserDetailsAuthenticationProvider;
import com.yami.shop.security.service.YamiUserDetailsService;
import lombok.AllArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
/**
*
* @author LGH
*/
@Component
@AllArgsConstructor
public class AdminAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
private final YamiUserDetailsService yamiUserDetailsService;
private final PasswordEncoder passwordEncoder;
@Override
protected UserDetails retrieveUser(String username, Authentication authentication) throws BaseYamiAuth2Exception {
AdminAuthenticationToken adminAuthenticationToken = (AdminAuthenticationToken) authentication;
String kaptchaKey = SecurityConstants.SPRING_SECURITY_RESTFUL_IMAGE_CODE + adminAuthenticationToken.getSessionUUID();
String kaptcha = RedisUtil.get(kaptchaKey);
RedisUtil.del(kaptchaKey);
if(StrUtil.isBlank(adminAuthenticationToken.getImageCode()) || !adminAuthenticationToken.getImageCode().equalsIgnoreCase(kaptcha)){
throw new ImageCodeNotMatchExceptionBase("验证码有误");
}
UserDetails user;
try {
user = yamiUserDetailsService.loadUserByUsername(username);
} catch (UsernameNotFoundExceptionBase var6) {
throw new UsernameNotFoundExceptionBase("账号或密码不正确");
}
String encodedPassword = user.getPassword();
String rawPassword = authentication.getCredentials().toString();
// 密码不正确
if (!passwordEncoder.matches(rawPassword,encodedPassword)){
throw new BadCredentialsExceptionBase("账号或密码不正确");
}
if (!user.isEnabled()) {
throw new UsernameNotFoundExceptionBase("账号已被锁定,请联系管理员");
}
return user;
}
@Override
protected Authentication createSuccessAuthentication(Authentication authentication, UserDetails user) {
AdminAuthenticationToken result = new AdminAuthenticationToken(user, authentication.getCredentials());
result.setDetails(authentication.getDetails());
return result;
}
@Override
public boolean supports(Class<?> authentication) {
return AdminAuthenticationToken.class.isAssignableFrom(authentication);
}
@Override
protected App getAppInfo() {
return null;
}
}

@ -1,21 +0,0 @@
package com.yami.shop.admin.security;
import com.yami.shop.common.util.Json;
import com.yami.shop.security.provider.AuthenticationTokenParser;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.stereotype.Component;
/**
* AdminAuthenticationTokenParser
*
* @author hanfeng
* @date 2019-08-21
*/
@Component
public class AdminAuthenticationTokenParser implements AuthenticationTokenParser {
@Override
public AbstractAuthenticationToken parse(String authenticationTokenStr) {
AdminAuthenticationToken authRequest = Json.parseObject(authenticationTokenStr, AdminAuthenticationToken.class);
return authRequest;
}
}

@ -0,0 +1,31 @@
package com.yami.shop.admin.security;
import com.yami.shop.security.service.YamiSysUser;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* token
* @author LGH
*/
@Component
public class AdminTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
final Map<String, Object> additionalInfo = new HashMap<>(8);
YamiSysUser yamiSysUser = (YamiSysUser) authentication.getUserAuthentication().getPrincipal();
additionalInfo.put("shopId", yamiSysUser.getShopId());
additionalInfo.put("userId", yamiSysUser.getUserId());
additionalInfo.put("authorities", yamiSysUser.getAuthorities());
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
return accessToken;
}
}

@ -1,143 +0,0 @@
/*
* Copyright (c) 2018-2999 广 All rights reserved.
*
* https://www.gz-yami.com/
*
*
*
*
*/
package com.yami.shop.admin.security;
import com.yami.shop.security.constants.SecurityConstants;
import com.yami.shop.security.service.YamiClientDetailsService;
import com.yami.shop.security.service.YamiSysUser;
import com.yami.shop.security.service.YamiUser;
import com.yami.shop.security.service.YamiUserDetailsService;
import com.yami.shop.security.util.YamiTokenServices;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
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.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
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.Collections;
import java.util.HashMap;
import java.util.Map;
@Configuration
//@Order(2)
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private YamiUserDetailsService yamiUserDetailsService;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private DataSource dataSource;
@Autowired
private RedisConnectionFactory redisConnectionFactory;
private AuthorizationServerEndpointsConfigurer endpoints;
@Bean
public TokenStore tokenStore() {
RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory);
tokenStore.setPrefix(SecurityConstants.YAMI_PREFIX + SecurityConstants.OAUTH_PREFIX);
return tokenStore;
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 使用JdbcClientDetailsService客户端详情服务
YamiClientDetailsService clientDetailsService = new YamiClientDetailsService(dataSource);
clientDetailsService.setSelectClientDetailsSql(SecurityConstants.DEFAULT_SELECT_STATEMENT);
clientDetailsService.setFindClientDetailsSql(SecurityConstants.DEFAULT_FIND_STATEMENT);
clients.withClientDetails(clientDetailsService);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.tokenEnhancer(tokenEnhancer())
.reuseRefreshTokens(false)
.userDetailsService(yamiUserDetailsService);
this.endpoints = endpoints;
endpoints.tokenServices(yamiTokenServices());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer
// 开启/oauth/token_key验证端口无权限访问
.tokenKeyAccess("permitAll()")
// 开启/oauth/check_token验证端口认证权限访问
.checkTokenAccess("isAuthenticated()");
}
/**
* token
*
* @return TokenEnhancer
*/
@Bean
public TokenEnhancer tokenEnhancer() {
return (accessToken, authentication) -> {
final Map<String, Object> additionalInfo = new HashMap<>(8);
YamiSysUser yamiSysUser = (YamiSysUser) authentication.getUserAuthentication().getPrincipal();
additionalInfo.put("shopId", yamiSysUser.getShopId());
additionalInfo.put("userId", yamiSysUser.getUserId());
additionalInfo.put("authorities", yamiSysUser.getAuthorities());
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
return accessToken;
};
}
@Primary
@Bean
@Lazy
public AuthorizationServerTokenServices yamiTokenServices() {
YamiTokenServices tokenServices = new YamiTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(true);//支持刷新token
tokenServices.setReuseRefreshToken(true);
// tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
addUserDetailsService(tokenServices);
return tokenServices;
}
private void addUserDetailsService(YamiTokenServices tokenServices) {
PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
provider.setPreAuthenticatedUserDetailsService(new UserDetailsByNameServiceWrapper<>(
yamiUserDetailsService));
tokenServices.setAuthenticationManager(new ProviderManager(Collections.singletonList(provider)));
}
}

@ -0,0 +1,157 @@
/*
* Copyright (c) 2018-2999 广 All rights reserved.
*
* https://www.gz-yami.com/
*
*
*
*
*/
package com.yami.shop.admin.security;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.yami.shop.common.util.Json;
import com.yami.shop.common.util.RedisUtil;
import com.yami.shop.security.constants.SecurityConstants;
import com.yami.shop.security.exception.BadCredentialsExceptionBase;
import com.yami.shop.security.exception.ImageCodeNotMatchExceptionBase;
import com.yami.shop.security.exception.UsernameNotFoundExceptionBase;
import com.yami.shop.security.provider.AuthenticationTokenParser;
import com.yami.shop.security.service.YamiUserDetailsService;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
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;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* principalcode
* post:http://127.0.0.1:8086/login
* {principal:code}
*
* post: http://127.0.0.1:8086/login
* {principal:username,credentials:password}
*/
@Component
public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private YamiUserDetailsService yamiUserDetailsService;
private PasswordEncoder passwordEncoder;
@Autowired
public LoginAuthenticationFilter(YamiUserDetailsService yamiUserDetailsService, PasswordEncoder passwordEncoder) {
super("/login");
this.yamiUserDetailsService = yamiUserDetailsService;
this.passwordEncoder = passwordEncoder;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (!ServletUtil.METHOD_POST.equals(request.getMethod())) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
String requestBody = getStringFromStream(request);
if (StrUtil.isBlank(requestBody)) {
throw new AuthenticationServiceException("无法获取输入信息");
}
AdminAuthenticationToken adminAuthenticationToken = Json.parseObject(requestBody, AdminAuthenticationToken.class);
String username = adminAuthenticationToken.getPrincipal() == null?"NONE_PROVIDED":adminAuthenticationToken.getName();
String kaptchaKey = SecurityConstants.SPRING_SECURITY_RESTFUL_IMAGE_CODE + adminAuthenticationToken.getSessionUUID();
String kaptcha = RedisUtil.get(kaptchaKey);
RedisUtil.del(kaptchaKey);
if(StrUtil.isBlank(adminAuthenticationToken.getImageCode()) || !adminAuthenticationToken.getImageCode().equalsIgnoreCase(kaptcha)){
throw new ImageCodeNotMatchExceptionBase("验证码有误");
}
UserDetails user;
try {
user = yamiUserDetailsService.loadUserByUsername(username);
} catch (UsernameNotFoundExceptionBase var6) {
throw new UsernameNotFoundExceptionBase("账号或密码不正确");
}
String encodedPassword = user.getPassword();
String rawPassword = adminAuthenticationToken.getCredentials().toString();
// 密码不正确
if (!passwordEncoder.matches(rawPassword,encodedPassword)){
throw new BadCredentialsExceptionBase("账号或密码不正确");
}
if (!user.isEnabled()) {
throw new UsernameNotFoundExceptionBase("账号已被锁定,请联系管理员");
}
AdminAuthenticationToken result = new AdminAuthenticationToken(user, adminAuthenticationToken.getCredentials());
result.setDetails(adminAuthenticationToken.getDetails());
return result;
}
private String getStringFromStream(HttpServletRequest req) {
ServletInputStream is;
try {
is = req.getInputStream();
int nRead = 1;
int nTotalRead = 0;
byte[] bytes = new byte[10240];
while (nRead > 0) {
nRead = is.read(bytes, nTotalRead, bytes.length - nTotalRead);
if (nRead > 0) {
nTotalRead = nTotalRead + nRead;
}
}
return new String(bytes, 0, nTotalRead, StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
@Override
@Autowired
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
super.setAuthenticationManager(authenticationManager);
}
@Override
@Autowired
public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler successHandler) {
super.setAuthenticationSuccessHandler(successHandler);
}
@Override
@Autowired
public void setAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
super.setAuthenticationFailureHandler(failureHandler);
}
}

@ -10,7 +10,6 @@
package com.yami.shop.admin.security; package com.yami.shop.admin.security;
import com.yami.shop.security.filter.LoginAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;

@ -0,0 +1,35 @@
package com.yami.shop.api.security;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.emoji.EmojiUtil;
import com.yami.shop.security.service.YamiUser;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* token
* @author LGH
*/
@Component
public class ApiTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
Map<String, Object> additionalInfo = new HashMap<>(8);
YamiUser yamiUser = (YamiUser) authentication.getUserAuthentication().getPrincipal();
additionalInfo.put("userId", yamiUser.getUserId());
additionalInfo.put("nickName", EmojiUtil.toUnicode(StrUtil.isBlank(yamiUser.getName())? "" : yamiUser.getName()));
additionalInfo.put("pic",yamiUser.getPic());
additionalInfo.put("enabled",yamiUser.isEnabled());
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
return accessToken;
}
}

@ -1,147 +0,0 @@
/*
* Copyright (c) 2018-2999 广 All rights reserved.
*
* https://www.gz-yami.com/
*
*
*
*
*/
package com.yami.shop.api.security;
import com.yami.shop.security.constants.SecurityConstants;
import com.yami.shop.security.service.YamiClientDetailsService;
import com.yami.shop.security.service.YamiUser;
import com.yami.shop.security.service.YamiUserDetailsService;
import com.yami.shop.security.util.YamiTokenServices;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
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.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.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
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.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
*
*/
@Configuration
//@Order(2)
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private YamiUserDetailsService yamiUserDetailsService;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private DataSource dataSource;
@Autowired
private RedisConnectionFactory redisConnectionFactory;
private AuthorizationServerEndpointsConfigurer endpoints;
@Bean
public TokenStore tokenStore() {
RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory);
tokenStore.setPrefix(SecurityConstants.YAMI_PREFIX + SecurityConstants.OAUTH_PREFIX);
return tokenStore;
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 使用JdbcClientDetailsService客户端详情服务
YamiClientDetailsService clientDetailsService = new YamiClientDetailsService(dataSource);
clientDetailsService.setSelectClientDetailsSql(SecurityConstants.DEFAULT_SELECT_STATEMENT);
clientDetailsService.setFindClientDetailsSql(SecurityConstants.DEFAULT_FIND_STATEMENT);
clients.withClientDetails(clientDetailsService);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.tokenEnhancer(tokenEnhancer())
// refresh_token需要userDetailsService
.reuseRefreshTokens(false)
.userDetailsService(yamiUserDetailsService);
this.endpoints = endpoints;
endpoints.tokenServices(yamiTokenServices());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer
// 开启/oauth/token_key验证端口无权限访问
.tokenKeyAccess("permitAll()")
// 开启/oauth/check_token验证端口认证权限访问
.checkTokenAccess("isAuthenticated()");
}
/**
* token
*
* @return TokenEnhancer
*/
@Bean
public TokenEnhancer tokenEnhancer() {
return (accessToken, authentication) -> {
Map<String, Object> additionalInfo = new HashMap<>(8);
YamiUser yamiUser = (YamiUser) authentication.getUserAuthentication().getPrincipal();
additionalInfo.put("userId", yamiUser.getUserId());
additionalInfo.put("nickName",yamiUser.getName());
additionalInfo.put("pic",yamiUser.getPic());
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
return accessToken;
};
}
@Primary
@Bean
@Lazy
public AuthorizationServerTokenServices yamiTokenServices() {
YamiTokenServices tokenServices = new YamiTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(true);//支持刷新token
tokenServices.setReuseRefreshToken(true);
// tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
addUserDetailsService(tokenServices);
return tokenServices;
}
private void addUserDetailsService(YamiTokenServices tokenServices) {
PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
provider.setPreAuthenticatedUserDetailsService(new UserDetailsByNameServiceWrapper<>(
yamiUserDetailsService));
tokenServices.setAuthenticationManager(new ProviderManager(Collections.singletonList(provider)));
}
}

@ -0,0 +1,154 @@
/*
* Copyright (c) 2018-2999 广 All rights reserved.
*
* https://www.gz-yami.com/
*
*
*
*
*/
package com.yami.shop.api.security;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.yami.shop.common.util.Json;
import com.yami.shop.common.util.RedisUtil;
import com.yami.shop.security.constants.SecurityConstants;
import com.yami.shop.security.enums.App;
import com.yami.shop.security.exception.BadCredentialsExceptionBase;
import com.yami.shop.security.exception.ImageCodeNotMatchExceptionBase;
import com.yami.shop.security.exception.UsernameNotFoundExceptionBase;
import com.yami.shop.security.exception.WxErrorExceptionBase;
import com.yami.shop.security.model.AppConnect;
import com.yami.shop.security.service.YamiUser;
import com.yami.shop.security.service.YamiUserDetailsService;
import com.yami.shop.security.token.MyAuthenticationToken;
import lombok.AllArgsConstructor;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* principalcode
* post:http://127.0.0.1:8086/login
* {principal:code}
*
* post: http://127.0.0.1:8086/login
* {principal:username,credentials:password}
*/
@Component
public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private final YamiUserDetailsService yamiUserDetailsService;
private final WxMaService wxMaService;
@Autowired
public LoginAuthenticationFilter(YamiUserDetailsService yamiUserDetailsService, WxMaService wxMaService) {
super("/login");
this.yamiUserDetailsService = yamiUserDetailsService;
this.wxMaService = wxMaService;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (!ServletUtil.METHOD_POST.equals(request.getMethod())) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
String requestBody = getStringFromStream(request);
if (StrUtil.isBlank(requestBody)) {
throw new AuthenticationServiceException("无法获取输入信息");
}
MiniAppAuthenticationToken authentication = Json.parseObject(requestBody, MiniAppAuthenticationToken.class);
String code = String.valueOf(authentication.getPrincipal());
YamiUser loadedUser = null;
WxMaJscode2SessionResult session = null;
AppConnect appConnect = new AppConnect();
appConnect.setAppId(App.MINI.value());
try {
session = wxMaService.getUserService().getSessionInfo(code);
loadedUser = yamiUserDetailsService.loadUserByAppIdAndBizUserId(App.MINI,session.getOpenid());
} catch (WxErrorException e) {
throw new WxErrorExceptionBase(e.getMessage());
} catch (UsernameNotFoundExceptionBase var6) {
if (session == null) {
throw new WxErrorExceptionBase("无法获取用户登陆信息");
}
appConnect.setBizUserId(session.getOpenid());
appConnect.setBizUnionid(session.getUnionid());
yamiUserDetailsService.insertUserIfNecessary(appConnect);
}
if (loadedUser == null) {
loadedUser = yamiUserDetailsService.loadUserByAppIdAndBizUserId(App.MINI, appConnect.getBizUserId());
}
MiniAppAuthenticationToken result = new MiniAppAuthenticationToken(loadedUser, authentication.getCredentials());
result.setDetails(authentication.getDetails());
return result;
}
private String getStringFromStream(HttpServletRequest req) {
ServletInputStream is;
try {
is = req.getInputStream();
int nRead = 1;
int nTotalRead = 0;
byte[] bytes = new byte[10240];
while (nRead > 0) {
nRead = is.read(bytes, nTotalRead, bytes.length - nTotalRead);
if (nRead > 0) {
nTotalRead = nTotalRead + nRead;
}
}
return new String(bytes, 0, nTotalRead, StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
@Override
@Autowired
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
super.setAuthenticationManager(authenticationManager);
}
@Override
@Autowired
public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler successHandler) {
super.setAuthenticationSuccessHandler(successHandler);
}
@Override
@Autowired
public void setAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
super.setAuthenticationFailureHandler(failureHandler);
}
}

@ -1,97 +0,0 @@
/*
* Copyright (c) 2018-2999 广 All rights reserved.
*
* https://www.gz-yami.com/
*
*
*
*
*/
package com.yami.shop.api.security;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.util.BooleanUtil;
import com.yami.shop.security.enums.App;
import com.yami.shop.security.exception.UsernameNotFoundExceptionBase;
import com.yami.shop.security.exception.WxErrorExceptionBase;
import com.yami.shop.security.model.AppConnect;
import com.yami.shop.security.provider.AbstractUserDetailsAuthenticationProvider;
import com.yami.shop.security.service.YamiUser;
import com.yami.shop.security.service.YamiUserDetailsService;
import com.yami.shop.security.token.MyAuthenticationToken;
import lombok.AllArgsConstructor;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
/**
*
* @author LGH
*/
@Component
@AllArgsConstructor
public class MiniAppAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
private final YamiUserDetailsService yamiUserDetailsService;
private final WxMaService wxMaService;
@Override
protected Authentication createSuccessAuthentication(Authentication authentication, UserDetails user) {
MiniAppAuthenticationToken result = new MiniAppAuthenticationToken(user, authentication.getCredentials());
result.setDetails(authentication.getDetails());
return result;
}
@Override
protected UserDetails retrieveUser(String code, Authentication authentication) throws AuthenticationException {
YamiUser loadedUser = null;
// 如果使用debugger 模式则返回debugger的用户
if (BooleanUtil.isTrue(((MyAuthenticationToken)authentication).getDebugger())) {
loadedUser = new YamiUser("1" , "debuggerOpenId1" , this.getAppInfo().value(), true);
loadedUser.setDebugger(true);
return loadedUser;
}
WxMaJscode2SessionResult session = null;
AppConnect appConnect = new AppConnect();
appConnect.setAppId(this.getAppInfo().value());
try {
session = wxMaService.getUserService().getSessionInfo(code);
loadedUser = yamiUserDetailsService.loadUserByAppIdAndBizUserId(this.getAppInfo(),session.getOpenid());
} catch (WxErrorException e) {
throw new WxErrorExceptionBase(e.getMessage());
} catch (UsernameNotFoundExceptionBase var6) {
if (session == null) {
throw new WxErrorExceptionBase("无法获取用户登陆信息");
}
appConnect.setBizUserId(session.getOpenid());
appConnect.setBizUnionid(session.getUnionid());
yamiUserDetailsService.insertUserIfNecessary(appConnect);
}
if (loadedUser == null) {
loadedUser = yamiUserDetailsService.loadUserByAppIdAndBizUserId(this.getAppInfo(), appConnect.getBizUserId());
}
return loadedUser;
}
@Override
public boolean supports(Class<?> authentication) {
return MiniAppAuthenticationToken.class.isAssignableFrom(authentication);
}
@Override
protected App getAppInfo() {
return App.MINI;
}
}

@ -1,21 +0,0 @@
package com.yami.shop.api.security;
import com.yami.shop.common.util.Json;
import com.yami.shop.security.provider.AuthenticationTokenParser;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.stereotype.Component;
/**
* MiniAppAuthenticationTokenParser
*
* @author hanfeng
* @date 2019-08-21
*/
@Component
public class MiniAppAuthenticationTokenParser implements AuthenticationTokenParser {
@Override
public AbstractAuthenticationToken parse(String authenticationTokenStr) {
MiniAppAuthenticationToken authRequest = Json.parseObject(authenticationTokenStr, MiniAppAuthenticationToken.class);
return authRequest;
}
}

@ -10,7 +10,6 @@
package com.yami.shop.api.security; package com.yami.shop.api.security;
import com.yami.shop.security.filter.LoginAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;

@ -0,0 +1,76 @@
/*
* Copyright (c) 2018-2999 广 All rights reserved.
*
* https://www.gz-yami.com/
*
*
*
*
*/
package com.yami.shop.security.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
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.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
/**
* @author LGH
*/
@Configuration
//@Order(2)
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private TokenStore tokenStore;
@Autowired
private AuthorizationServerTokenServices yamiTokenServices;
@Autowired
private TokenEnhancer tokenEnhancer;
@Autowired
private UserDetailsService userDetailsService;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore)
.tokenEnhancer(tokenEnhancer)
// refresh_token需要userDetailsService
.reuseRefreshTokens(false)
.userDetailsService(userDetailsService);
endpoints.tokenServices(yamiTokenServices);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer
// 开启/oauth/token_key验证端口无权限访问
.tokenKeyAccess("permitAll()")
// 开启/oauth/check_token验证端口认证权限访问
.checkTokenAccess("isAuthenticated()");
}
}

@ -0,0 +1,66 @@
package com.yami.shop.security.config;
import com.yami.shop.security.constants.SecurityConstants;
import com.yami.shop.security.util.YamiTokenServices;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
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.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
import java.util.Collections;
/**
* @author LGH
*/
@Configuration
public class TokenConfig {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Autowired
private TokenEnhancer tokenEnhancer;
@Bean
public TokenStore tokenStore() {
RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory);
tokenStore.setPrefix(SecurityConstants.YAMI_OAUTH_PREFIX);
return tokenStore;
}
@Primary
@Bean
@Lazy
public AuthorizationServerTokenServices yamiTokenServices() {
YamiTokenServices tokenServices = new YamiTokenServices();
tokenServices.setTokenStore(tokenStore());
//支持刷新token
tokenServices.setSupportRefreshToken(true);
tokenServices.setReuseRefreshToken(true);
tokenServices.setTokenEnhancer(tokenEnhancer);
addUserDetailsService(tokenServices);
return tokenServices;
}
private void addUserDetailsService(YamiTokenServices tokenServices) {
PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
provider.setPreAuthenticatedUserDetailsService(new UserDetailsByNameServiceWrapper<>(userDetailsService));
tokenServices.setAuthenticationManager(new ProviderManager(Collections.singletonList(provider)));
}
}

@ -11,39 +11,23 @@
package com.yami.shop.security.config; package com.yami.shop.security.config;
import com.yami.shop.security.filter.LoginAuthenticationFilter;
import com.yami.shop.security.handler.LoginAuthFailedHandler;
import com.yami.shop.security.handler.LoginAuthSuccessHandler;
import com.yami.shop.security.provider.AuthenticationTokenParser;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.factory.PasswordEncoderFactories; import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @author LGH
*/
@Configuration @Configuration
@Order(90) @Order(90)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private LoginAuthSuccessHandler loginAuthSuccessHandler;
@Autowired
private LoginAuthFailedHandler loginAuthFailedHandler;
@Autowired
private AuthenticationProvider authenticationProvider;
@Autowired
private AuthenticationTokenParser authenticationTokenParser;
@Override @Override
@Bean @Bean
@SneakyThrows @SneakyThrows
@ -51,33 +35,9 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
return super.authenticationManagerBean(); return super.authenticationManagerBean();
} }
/**
*
* @param auth
*/
@Override
public void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(authenticationProvider);
}
@Bean @Bean
public PasswordEncoder passwordEncoder(){ public PasswordEncoder passwordEncoder(){
return PasswordEncoderFactories.createDelegatingPasswordEncoder(); return PasswordEncoderFactories.createDelegatingPasswordEncoder();
} }
@Bean
public LoginAuthenticationFilter loginAuthenticationFilter() {
LoginAuthenticationFilter filter = new LoginAuthenticationFilter();
try {
filter.setAuthenticationManager(authenticationManagerBean());
} catch (Exception e) {
e.printStackTrace();
}
filter.setAuthenticationSuccessHandler(loginAuthSuccessHandler);
filter.setAuthenticationFailureHandler(loginAuthFailedHandler);
filter.setAuthenticationTokenParser(authenticationTokenParser);
return filter;
}
} }

@ -11,56 +11,11 @@
package com.yami.shop.security.constants; package com.yami.shop.security.constants;
public interface SecurityConstants { public interface SecurityConstants {
/**
*
*/
String YAMI_PREFIX = "yami_";
/** /**
* oauth * oauth
*/ */
String OAUTH_PREFIX = "oauth:"; String YAMI_OAUTH_PREFIX = "yami_oauth:";
/**
* oauth
*/
String CLIENT_DETAILS_KEY = "yami_oauth:client:details";
/**
* sys_oauth_client_details client_idclient_secret
*/
String CLIENT_FIELDS = "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";
/**
* JdbcClientDetailsService
*/
String BASE_FIND_STATEMENT = "select " + CLIENT_FIELDS
+ " from tz_oauth_client_details";
/**
*
*/
String DEFAULT_FIND_STATEMENT = BASE_FIND_STATEMENT + " order by client_id";
/**
* client_id
*/
String DEFAULT_SELECT_STATEMENT = BASE_FIND_STATEMENT + " where client_id = ?";
/**
* (tz_oauth_client_details )
*/
String SPRING_SECURITY_RESTFUL_TYPE_MINI_APP = "mini_app";
/**
* (tz_oauth_client_details )
*/
String SPRING_SECURITY_RESTFUL_TYPE_MP = "weixin_mp";
/**
* (tz_oauth_client_details )
*/
String SPRING_SECURITY_RESTFUL_TYPE_ADMIN = "admin";
String SPRING_SECURITY_RESTFUL_IMAGE_CODE = "imageCode"; String SPRING_SECURITY_RESTFUL_IMAGE_CODE = "imageCode";
} }

@ -1,86 +0,0 @@
/*
* Copyright (c) 2018-2999 广 All rights reserved.
*
* https://www.gz-yami.com/
*
*
*
*
*/
package com.yami.shop.security.filter;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.yami.shop.security.provider.AuthenticationTokenParser;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* principalcode
* post:http://127.0.0.1:8086/login
* {principal:code}
*
* post: http://127.0.0.1:8086/login
* {principal:username,credentials:password}
*/
public class LoginAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationTokenParser authenticationTokenParser;
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (!ServletUtil.METHOD_POST.equals(request.getMethod())) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
String requestBody = getStringFromStream(request);
if (StrUtil.isBlank(requestBody)) {
throw new AuthenticationServiceException("无法获取输入信息");
}
AbstractAuthenticationToken authRequest = authenticationTokenParser.parse(requestBody);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
private void setDetails(HttpServletRequest request,
AbstractAuthenticationToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}
private String getStringFromStream(HttpServletRequest req) {
ServletInputStream is;
try {
is = req.getInputStream();
int nRead = 1;
int nTotalRead = 0;
byte[] bytes = new byte[10240];
while (nRead > 0) {
nRead = is.read(bytes, nTotalRead, bytes.length - nTotalRead);
if (nRead > 0) {
nTotalRead = nTotalRead + nRead;
}
}
return new String(bytes, 0, nTotalRead, StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
public void setAuthenticationTokenParser(AuthenticationTokenParser authenticationTokenParser) {
this.authenticationTokenParser = authenticationTokenParser;
}
}

@ -60,31 +60,13 @@ public class LoginAuthSuccessHandler implements AuthenticationSuccessHandler {
try { try {
// ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId); TokenRequest tokenRequest = new TokenRequest(null, null, null, null);
String grantType = request.getParameter(OAuth2Utils.GRANT_TYPE);
// 目前先简化登陆传入的参数
String clientId = grantType;
// 简化 // 简化
BaseClientDetails clientDetails = new BaseClientDetails(); OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(new BaseClientDetails());
clientDetails.setClientId(clientId);
TokenRequest tokenRequest = new TokenRequest(MapUtil.newHashMap(), clientId, Sets.newHashSet(), grantType);
OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);
OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication); OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);
// OAuth2AccessToken accessToken = defaultAuthorizationServerTokenServices.getAccessToken(oAuth2Authentication);
// OAuth2AccessToken oAuth2AccessToken = null;
// if (accessToken != null) {
// oAuth2AccessToken = defaultAuthorizationServerTokenServices.refreshAccessToken(accessToken.getRefreshToken().getValue(), tokenRequest);
// } else {
// oAuth2AccessToken = defaultAuthorizationServerTokenServices.createAccessToken(oAuth2Authentication);
// }
OAuth2AccessToken oAuth2AccessToken = yamiTokenServices.createAccessToken(oAuth2Authentication); OAuth2AccessToken oAuth2AccessToken = yamiTokenServices.createAccessToken(oAuth2Authentication);
log.info("获取token 成功:{}", oAuth2AccessToken.getValue()); log.info("获取token 成功:{}", oAuth2AccessToken.getValue());

@ -29,18 +29,4 @@ public class YamiClientDetailsService extends JdbcClientDetailsService {
public YamiClientDetailsService(DataSource dataSource) { public YamiClientDetailsService(DataSource dataSource) {
super(dataSource); super(dataSource);
} }
/**
* redis
*
* @param clientId
* @return tz_oauth_client_details
* @throws InvalidClientException
*/
@Override
@SneakyThrows
@Cacheable(value = SecurityConstants.CLIENT_DETAILS_KEY, key = "#clientId", unless = "#result == null")
public ClientDetails loadClientByClientId(String clientId) {
return super.loadClientByClientId(clientId);
}
} }

Loading…
Cancel
Save