Skip to content

Commit

Permalink
feat: 支持从微信登录,增加获取当前已购买专栏的接口
Browse files Browse the repository at this point in the history
  • Loading branch information
lichong-a committed Oct 8, 2024
1 parent e620721 commit 341db0e
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class ApplicationConfig {
@NestedConfigurationProperty
private final Security security;

public static final String WECHAT_LOGIN_URL_TEMPLATE = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";
public static final String WECHAT_LOGIN_URL_TEMPLATE = "https://api.weixin.qq.com/sns/jscode2session?appid={appid}&secret={secret}&js_code={js_code}&grant_type={grant_type}";

/**
* @param adminUsername 管理员用户名
Expand Down Expand Up @@ -68,15 +68,4 @@ public record WeChat(String appId,
}
}

/**
* 生成微信登录请求地址
*
* @param code code
* @return 请求地址
*/
public String wechatLoginUrl(String code) {
return String.format(WECHAT_LOGIN_URL_TEMPLATE, security.weChat.appId, security.weChat.appSecret, code);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestClient;
import org.springframework.web.client.RestTemplate;

/**
Expand All @@ -23,4 +24,9 @@ public class HttpRequestConfig {
public RestTemplate restTemplate() {
return new RestTemplate();
}

@Bean
public RestClient restClient() {
return RestClient.create();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
Expand All @@ -38,6 +39,8 @@
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import java.util.List;

import static org.funcode.portal.server.common.core.security.filter.WechatAuthenticationFilter.WECHAT_LOGIN_PATH;
import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS;
import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher;
Expand Down Expand Up @@ -128,8 +131,8 @@ public WechatAuthenticationFilter weChatAuthenticationFilter(AuthenticationManag
}

@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
public AuthenticationManager authenticationManager(List<AuthenticationProvider> authenticationProviders) {
return new ProviderManager(authenticationProviders);
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ protected void doFilterInternal(@NonNull HttpServletRequest request,
// 获取 token,优先从 cookie 获取,其次从 header 获取
String accessTokenCookie = CookieUtils.getCookieValue(request, SecurityConstant.TOKEN_COOKIE_KEY);
final String accessToken = StringUtils.isBlank(accessTokenCookie) ? request.getHeader(SecurityConstant.TOKEN_HEADER_KEY) : accessTokenCookie;
// 没 token 场景为 登录 等,直接放行,因为后边有其他的过滤器
if (StringUtils.isBlank(accessToken)) {
// 没 token 场景为 登录 或 匿名 等,直接放行,因为后边有其他的过滤器
if (StringUtils.isBlank(accessToken) ) {
filterChain.doFilter(request, response);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,22 @@
import org.apache.commons.lang3.StringUtils;
import org.funcode.portal.server.common.core.config.ApplicationConfig;
import org.funcode.portal.server.common.core.security.domain.WechatAuthenticationToken;
import org.funcode.portal.server.common.core.security.service.IRoleService;
import org.funcode.portal.server.common.core.security.service.IUserService;
import org.funcode.portal.server.common.domain.security.Role;
import org.funcode.portal.server.common.domain.security.Role_;
import org.funcode.portal.server.common.domain.security.User;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.client.RestClient;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.*;

/**
* @author 李冲
Expand All @@ -35,9 +38,10 @@
@Component
@RequiredArgsConstructor
public class WeChatAuthenticationProvider implements AuthenticationProvider {
private final RestTemplate restTemplate;
private final RestClient restClient;
private final ApplicationConfig applicationConfig;
private final IUserService userService;
private final IRoleService roleService;

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Expand All @@ -46,18 +50,34 @@ public Authentication authenticate(Authentication authentication) throws Authent
String loginCode = wechatAuthenticationToken.getPrincipal().toString();
log.info("loginCode is {}", loginCode);
//获取openId
String wechatLoginUrl = applicationConfig.wechatLoginUrl(loginCode);
ResponseEntity<String> responseEntity = restTemplate.getForEntity(wechatLoginUrl, String.class);
String wechatLoginUrl = ApplicationConfig.WECHAT_LOGIN_URL_TEMPLATE;
Map<String, String> requestParams = Map.of("appid", applicationConfig.getSecurity().weChat().appId(),
"secret", applicationConfig.getSecurity().weChat().appSecret(),
"js_code", loginCode,
"grant_type", "authorization_code");
ResponseEntity<String> responseEntity = restClient
.get()
.uri(wechatLoginUrl, requestParams)
.retrieve()
.toEntity(String.class);
JsonObject jsonObject = new Gson().fromJson(responseEntity.getBody(), JsonObject.class);
log.info(jsonObject.getAsString());
String openId = jsonObject.get("openid").getAsString();
log.info(jsonObject.toString());
String openId = jsonObject.get("openid") == null ? "" : jsonObject.get("openid").getAsString();
if (StringUtils.isBlank(openId)) {
throw new BadCredentialsException("WeChat get openId error");
}
User user = userService.findByWechatId(openId);
List<Role> roles = roleService.findList((Specification<Role>) (root, query, criteriaBuilder) -> query.where(root.get(Role_.roleKey).in(List.of("admin", "student"))).getRestriction());
if (user == null) {
// 人员不存在
throw new BadCredentialsException("user not exists");
// 人员不存在就新建人员
User newUser = User.builder()
.wechatId(openId)
.username(openId)
.password(openId)
.roles(new HashSet<>(roles))
.build();
userService.save(newUser);
user = newUser;
}
return getAuthenticationToken(openId, user, user.getAuthorities());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
Expand Down Expand Up @@ -84,7 +83,7 @@ public boolean isTokenExpired(String token) {
@Transactional
public void filterVerifyAccessToken(@NonNull String accessToken,
@NonNull HttpServletRequest request,
@NonNull HttpServletResponse response) throws IOException, ServletException {
@NonNull HttpServletResponse response) throws IOException {
SecurityContext context = SecurityContextHolder.createEmptyContext();
try {
String username = this.extractUserName(accessToken);
Expand All @@ -100,6 +99,7 @@ public void filterVerifyAccessToken(@NonNull String accessToken,
if (this.isTokenValid(accessToken, userDetails)) {
// 保存登录状态到当前上下文
SecurityContextHolder.setContext(context);
response.setHeader(SecurityConstant.TOKEN_HEADER_KEY, accessToken);
}
}
} catch (ExpiredJwtException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
* @author 李冲
* @see <a href="https://lichong.work">李冲博客</a>
Expand Down Expand Up @@ -66,4 +68,10 @@ public ResponseResult<Page<CourseColumn>> pageList(@Valid @RequestBody CourseCol
public ResponseResult<Page<CourseColumn>> pageListAnonymous(@Valid PageRequestVo pageRequestVo) {
return ResponseResult.success(courseColumnService.findPage(pageRequestVo));
}

@Operation(summary = "查询当前登录人已购买的专栏")
@GetMapping("list/purchased")
public ResponseResult<List<CourseColumn>> pageListPurchased() {
return ResponseResult.success(courseColumnService.listPurchased());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import org.funcode.portal.server.module.ielts.column.domain.vo.CourseColumnQueryVo;
import org.springframework.data.domain.Page;

import java.util.List;

/**
* @author 李冲
* @see <a href="https://lichong.work">李冲博客</a>
Expand Down Expand Up @@ -43,4 +45,10 @@ public interface ICourseColumnService extends IBaseService<CourseColumn, Long> {
*/
Page<CourseColumn> findPage(PageRequestVo pageRequestVo);

/**
* 查询当前登录人已购买的专栏
*
* @return 专栏列表
*/
List<CourseColumn> listPurchased();
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@

import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.funcode.portal.server.common.core.base.exception.BusinessException;
import org.funcode.portal.server.common.core.base.service.impl.BaseServiceImpl;
import org.funcode.portal.server.common.domain.base.PageRequestVo;
import org.funcode.portal.server.common.domain.ielts.Course;
import org.funcode.portal.server.common.domain.ielts.CourseColumn;
import org.funcode.portal.server.common.domain.ielts.CourseColumn_;
import org.funcode.portal.server.common.domain.ielts.Storage;
import org.funcode.portal.server.common.domain.security.User;
import org.funcode.portal.server.module.ielts.column.domain.vo.CourseColumnAddOrEditVo;
import org.funcode.portal.server.module.ielts.column.domain.vo.CourseColumnQueryVo;
import org.funcode.portal.server.module.ielts.column.repository.ICourseColumnRepository;
Expand All @@ -21,6 +23,7 @@
import org.funcode.portal.server.module.ielts.storage.repository.IStorageRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
Expand Down Expand Up @@ -83,6 +86,15 @@ public Page<CourseColumn> findPage(PageRequestVo pageRequestVo) {
);
}

@Override
public List<CourseColumn> listPurchased() {
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (currentUser == null) {
throw new BusinessException("当前用户未登录");
}
return currentUser.getCourseColumns().stream().sorted((a, b) -> b.getCreatedAt().compareTo(a.getCreatedAt())).toList();
}

private CourseColumn transAddOrEditVoToCourseColumn(CourseColumnAddOrEditVo courseColumnAddOrEditVo) {
Storage coverStorage = courseColumnAddOrEditVo.getCourseColumnCoverStorageId() != null ?
storageRepository.getReferenceById(courseColumnAddOrEditVo.getCourseColumnCoverStorageId())
Expand Down

0 comments on commit 341db0e

Please sign in to comment.