feat:整合oauth2和knife4j

This commit is contained in:
hxrui 2021-02-26 14:20:08 +08:00
parent d5b77d0905
commit 4bd06272cd
16 changed files with 132 additions and 83 deletions

View File

@ -1,7 +1,7 @@
package com.youlai.mall.pms.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.youlai.common.web.vo.CascaderVO;
import com.youlai.common.web.pojo.vo.CascaderVO;
import com.youlai.mall.pms.pojo.PmsCategory;
import com.youlai.mall.pms.pojo.vo.CategoryVO;

View File

@ -3,7 +3,7 @@ package com.youlai.mall.pms.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.common.web.vo.CascaderVO;
import com.youlai.common.web.pojo.vo.CascaderVO;
import com.youlai.mall.pms.pojo.PmsCategory;
import com.youlai.mall.pms.mapper.PmsCategoryMapper;
import com.youlai.mall.pms.service.IPmsCategoryService;

View File

@ -3,7 +3,7 @@ package com.youlai.mall.ums.controller.app;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.youlai.common.result.Result;
import com.youlai.common.web.util.WebUtils;
import com.youlai.common.web.util.RequestUtils;
import com.youlai.mall.ums.pojo.UmsAddress;
import com.youlai.mall.ums.service.IUmsAddressService;
import io.swagger.annotations.Api;
@ -30,7 +30,7 @@ public class AppAddressController {
@ApiOperation(value = "获取当前登录会员的地址列表", httpMethod = "GET")
@GetMapping
public Result list() {
Long userId = WebUtils.getUserId();
Long userId = RequestUtils.getUserId();
List<UmsAddress> addressList = iUmsAddressService.list(new LambdaQueryWrapper<UmsAddress>()
.eq(UmsAddress::getUserId, userId)
.orderByDesc(UmsAddress::getDefaulted));
@ -42,7 +42,7 @@ public class AppAddressController {
@ApiImplicitParam(name = "address", value = "实体JSON对象", required = true, paramType = "body", dataType = "UmsAddress")
@PostMapping
public Result add(@RequestBody UmsAddress address) {
Long userId = WebUtils.getUserId();
Long userId = RequestUtils.getUserId();
address.setUserId(userId);
if (address.getDefaulted().equals(1)) { // 修改其他默认地址为非默认
iUmsAddressService.update(new LambdaUpdateWrapper<UmsAddress>()
@ -65,7 +65,7 @@ public class AppAddressController {
public Result update(
@PathVariable Long id,
@RequestBody UmsAddress address) {
Long userId = WebUtils.getUserId();
Long userId = RequestUtils.getUserId();
if (address.getDefaulted().equals(1)) { // 修改其他默认地址为非默认
iUmsAddressService.update(new LambdaUpdateWrapper<UmsAddress>()
.eq(UmsAddress::getUserId, userId)
@ -93,7 +93,7 @@ public class AppAddressController {
})
@PatchMapping(value = "/{id}")
public Result patch(@PathVariable Long id, @RequestBody UmsAddress address) {
Long userId = WebUtils.getUserId();
Long userId = RequestUtils.getUserId();
LambdaUpdateWrapper<UmsAddress> updateWrapper = new LambdaUpdateWrapper<UmsAddress>()
.eq(UmsAddress::getUserId, userId);
if (address.getDefaulted() != null) {

View File

@ -4,7 +4,7 @@ import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.youlai.common.result.Result;
import com.youlai.common.result.ResultCode;
import com.youlai.common.web.util.WebUtils;
import com.youlai.common.web.util.RequestUtils;
import com.youlai.mall.ums.pojo.UmsUser;
import com.youlai.mall.ums.pojo.dto.AuthMemberDTO;
import com.youlai.mall.ums.pojo.dto.MemberDTO;
@ -72,7 +72,7 @@ public class AppUserController {
@ApiOperation(value = "获取当前请求的会员信息", httpMethod = "GET")
@GetMapping("/me")
public Result getMemberInfo() {
Long userId = WebUtils.getUserId();
Long userId = RequestUtils.getUserId();
UmsUser user = iUmsUserService.getById(userId);
if (user == null) {
return Result.failed(ResultCode.USER_NOT_EXIST);

View File

@ -13,10 +13,9 @@ import com.youlai.admin.pojo.dto.UserDTO;
import com.youlai.admin.pojo.vo.UserVO;
import com.youlai.admin.service.*;
import com.youlai.common.base.BaseController;
import com.youlai.common.constant.GlobalConstants;
import com.youlai.common.result.Result;
import com.youlai.common.result.ResultCode;
import com.youlai.common.web.util.WebUtils;
import com.youlai.common.web.util.RequestUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
@ -171,11 +170,11 @@ public class UserController extends BaseController {
public Result<UserVO> getCurrentUser() {
UserVO userVO = new UserVO();
Long userId = WebUtils.getUserId();
Long userId = RequestUtils.getUserId();
SysUser user = iSysUserService.getById(userId);
BeanUtil.copyProperties(user, userVO);
List<Long> roleIds = WebUtils.getRoleIds();
List<Long> roleIds = RequestUtils.getRoleIds();
List<String> perms = iSysPermissionService.listPermsByRoleIds(roleIds, PermTypeEnum.BUTTON.getValue());
userVO.setRoles(roleIds);
userVO.setPerms(perms);

View File

@ -147,7 +147,7 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
Map<String, Object> map = new HashMap<>(2);
User user = (User) authentication.getUserAuthentication().getPrincipal();
map.put(AuthConstants.JWT_USER_ID_KEY, user.getId());
map.put(AuthConstants.JWT_CLIENT_ID_KEY, user.getClientId());
map.put(AuthConstants.CLIENT_ID_KEY, user.getClientId());
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(map);
return accessToken;
};

View File

@ -44,7 +44,7 @@ public class SwaggerConfiguration {
scopes.add(new AuthorizationScope("writes","write all resources"));
SecurityReference securityReference=new SecurityReference("oauth2",scopes.toArray(new AuthorizationScope[]{}));
SecurityContext securityContext=new SecurityContext(Lists.newArrayList(securityReference),PathSelectors.ant("/api/**"));
SecurityContext securityContext=new SecurityContext(Lists.newArrayList(securityReference),PathSelectors.ant("/**"));
//schemas
List<SecurityScheme> securitySchemes=Lists.newArrayList(oAuth);
//securyContext

View File

@ -10,6 +10,7 @@ import com.youlai.common.constant.GlobalConstants;
import com.youlai.common.result.Result;
import com.youlai.common.result.ResultCode;
import com.youlai.common.web.exception.BizException;
import com.youlai.common.web.util.RequestUtils;
import com.youlai.mall.ums.api.MemberFeignService;
import com.youlai.mall.ums.pojo.UmsUser;
import com.youlai.mall.ums.pojo.dto.AuthMemberDTO;
@ -62,10 +63,13 @@ public class AuthController {
@ApiIgnore Principal principal,
@ApiIgnore @RequestParam Map<String, String> parameters
) throws HttpRequestMethodNotSupportedException {
String clientId = parameters.get(AuthConstants.JWT_CLIENT_ID_KEY);
String clientId = RequestUtils.getAuthClientId();
switch (clientId) {
case AuthConstants.WEAPP_CLIENT_ID: // 微信认证
return this.handleForWxAuth(principal, parameters);
default:
OAuth2AccessToken oAuth2AccessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody();
Oauth2Token oauth2Token = Oauth2Token.builder()

View File

@ -3,7 +3,7 @@ package com.youlai.auth.controller;
import cn.hutool.json.JSONObject;
import com.youlai.common.constant.AuthConstants;
import com.youlai.common.result.Result;
import com.youlai.common.web.util.WebUtils;
import com.youlai.common.web.util.RequestUtils;
import io.swagger.annotations.Api;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -26,7 +26,7 @@ public class LogoutController {
@DeleteMapping("/logout")
public Result logout() {
JSONObject jsonObject = WebUtils.getJwtPayload();
JSONObject jsonObject = RequestUtils.getJwtPayload();
String jti = jsonObject.getStr("jti"); // JWT唯一标识
long exp = jsonObject.getLong("exp"); // JWT过期时间戳

View File

@ -1,11 +1,13 @@
package com.youlai.auth.service;
import cn.hutool.core.util.StrUtil;
import com.youlai.admin.pojo.dto.UserDTO;
import com.youlai.admin.api.UserFeignService;
import com.youlai.auth.domain.User;
import com.youlai.common.constant.AuthConstants;
import com.youlai.common.result.Result;
import com.youlai.common.result.ResultCode;
import com.youlai.common.web.util.RequestUtils;
import com.youlai.mall.ums.pojo.dto.AuthMemberDTO;
import com.youlai.mall.ums.api.MemberFeignService;
import lombok.AllArgsConstructor;
@ -16,6 +18,7 @@ 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;
import javax.servlet.http.HttpServletRequest;
@ -29,12 +32,10 @@ public class UserDetailsServiceImpl implements UserDetailsService {
private UserFeignService userFeignService;
private MemberFeignService memberFeignService;
private HttpServletRequest request;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
String clientId = RequestUtils.getAuthClientId();
String clientId = request.getParameter(AuthConstants.JWT_CLIENT_ID_KEY);
User user = null;
switch (clientId) {
case AuthConstants.ADMIN_CLIENT_ID: // 后台用户

View File

@ -4,14 +4,20 @@ public interface AuthConstants {
/**
* 认证信息Http请求头
* 认证请求头key
*/
String JWT_TOKEN_HEADER = "Authorization";
String AUTHORIZATION_KEY = "Authorization";
/**
* JWT令牌前缀
*/
String JWT_TOKEN_PREFIX = "Bearer ";
String JWT_PREFIX = "Bearer ";
/**
* Basic认证前缀
*/
String BASIC_PREFIX = "Basic ";
/**
* JWT载体key
@ -43,11 +49,9 @@ public interface AuthConstants {
*/
String BCRYPT = "{bcrypt}";
String JWT_USER_ID_KEY = "id";
String JWT_USER_ID_KEY = "user_id";
String JWT_CLIENT_ID_KEY = "client_id";
String JWT_JTI_KEY = "client_id";
String CLIENT_ID_KEY = "client_id";
/**
* JWT存储权限前缀
@ -63,16 +67,16 @@ public interface AuthConstants {
/**
* 有来商城后台管理客户端ID
*/
String ADMIN_CLIENT_ID="youlai-admin";
String ADMIN_CLIENT_ID = "youlai-admin";
/**
* 有来商城微信小程序客户端ID
*/
String WEAPP_CLIENT_ID="youlai-mall-weapp";
String WEAPP_CLIENT_ID = "youlai-mall-weapp";
/**
* 后台管理接口路径匹配
*/
String ADMIN_URL_PATTERN ="*_/youlai-admin/**" ;
String ADMIN_URL_PATTERN = "*_/youlai-admin/**";
}

View File

@ -1,4 +1,4 @@
package com.youlai.common.web.vo;
package com.youlai.common.web.pojo.vo;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;

View File

@ -0,0 +1,86 @@
package com.youlai.common.web.util;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.youlai.common.constant.AuthConstants;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import sun.misc.BASE64Decoder;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
public class RequestUtils {
public static HttpServletRequest getHttpServletRequest() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
return request;
}
public static JSONObject getJwtPayload() {
String jwtPayload = getHttpServletRequest().getHeader(AuthConstants.JWT_PAYLOAD_KEY);
JSONObject jsonObject = JSONUtil.parseObj(jwtPayload);
return jsonObject;
}
public static Long getUserId() {
Long id = getJwtPayload().getLong(AuthConstants.JWT_USER_ID_KEY);
return id;
}
/**
* 获取JWT的载体中的clientId
*
* @return
*/
public static String getClientId() {
String clientId = getJwtPayload().getStr(AuthConstants.CLIENT_ID_KEY);
return clientId;
}
/**
* 获取登录认证的客户端ID
* <p>
* 兼容两种方式获取Oauth2客户端信息client_idclient_secret
* 方式一client_idclient_secret放在请求路径中
* 方式二放在请求头Request Headers中的Authorization字段且经过加密例如 Basic Y2xpZW50OnNlY3JldA== 明文等于 client:secret
*
* @return
*/
@SneakyThrows
public static String getAuthClientId() {
String clientId;
HttpServletRequest request = getHttpServletRequest();
// 从请求路径中获取
clientId = request.getParameter(AuthConstants.CLIENT_ID_KEY);
if (StrUtil.isNotBlank(clientId)) {
return clientId;
}
// 从请求头获取
String basic = request.getHeader(AuthConstants.AUTHORIZATION_KEY);
basic = request.getHeader(AuthConstants.AUTHORIZATION_KEY);
if (StrUtil.isNotBlank(basic) && basic.startsWith(AuthConstants.BASIC_PREFIX)) {
basic = basic.replace(AuthConstants.BASIC_PREFIX, Strings.EMPTY);
String basicPlainText = new String(new BASE64Decoder().decodeBuffer(basic), "UTF-8");
clientId = basicPlainText.split(":")[0]; //client:secret
}
return clientId;
}
public static List<Long> getRoleIds() {
List<String> list = getJwtPayload().get(AuthConstants.JWT_AUTHORITIES_KEY, List.class);
List<Long> authorities = list.stream().map(Long::valueOf).collect(Collectors.toList());
return authorities;
}
}

View File

@ -1,44 +0,0 @@
package com.youlai.common.web.util;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.youlai.common.constant.AuthConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
public class WebUtils extends org.springframework.web.util.WebUtils {
public static HttpServletRequest getHttpServletRequest() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
return request;
}
public static JSONObject getJwtPayload() {
String jwtPayload = getHttpServletRequest().getHeader(AuthConstants.JWT_PAYLOAD_KEY);
JSONObject jsonObject = JSONUtil.parseObj(jwtPayload);
return jsonObject;
}
public static Long getUserId() {
Long id = getJwtPayload().getLong(AuthConstants.JWT_USER_ID_KEY);
return id;
}
public static String getClientId() {
String clientId = getJwtPayload().getStr(AuthConstants.JWT_CLIENT_ID_KEY);
return clientId;
}
public static List<Long> getRoleIds() {
List<String> list = getJwtPayload().get(AuthConstants.JWT_AUTHORITIES_KEY, List.class);
List<Long> authorities = list.stream().map(Long::valueOf).collect(Collectors.toList());
return authorities;
}
}

View File

@ -45,24 +45,23 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
ServerHttpResponse response = exchange.getResponse();
// 演示环境禁止删除和修改
if (isDemoEnvironment &&
HttpMethod.DELETE.toString().equals(request.getMethodValue())) {
if (isDemoEnvironment &&HttpMethod.DELETE.toString().equals(request.getMethodValue())) {
log.warn(ResultCode.FORBIDDEN_OPERATION.getMsg());
return WebUtils.writeFailedToResponse(response, ResultCode.FORBIDDEN_OPERATION);
}
// 无token放行
String token = exchange.getRequest().getHeaders().getFirst(AuthConstants.JWT_TOKEN_HEADER);
if (StrUtil.isBlank(token) || !token.startsWith(AuthConstants.JWT_TOKEN_PREFIX)) {
String token = request.getHeaders().getFirst(AuthConstants.AUTHORIZATION_KEY);
if (StrUtil.isBlank(token) || !token.startsWith(AuthConstants.JWT_PREFIX)) {
return chain.filter(exchange);
}
// 解析JWT获取jti以jti为key判断redis的黑名单列表是否存在存在拦截响应token失效
token = token.replace(AuthConstants.JWT_TOKEN_PREFIX, Strings.EMPTY);
token = token.replace(AuthConstants.JWT_PREFIX, Strings.EMPTY);
JWSObject jwsObject = JWSObject.parse(token);
String payload = jwsObject.getPayload().toString();
JSONObject jsonObject = JSONUtil.parseObj(payload);
String jti = jsonObject.getStr(AuthConstants.JWT_JTI_KEY);
String jti = jsonObject.getStr(AuthConstants.CLIENT_ID_KEY);
Boolean isBlack = redisTemplate.hasKey(AuthConstants.TOKEN_BLACKLIST_PREFIX + jti);
if (isBlack) {
return WebUtils.writeFailedToResponse(response, ResultCode.TOKEN_INVALID_OR_EXPIRED);

View File

@ -54,7 +54,7 @@ public class AuthorizationManager implements ReactiveAuthorizationManager<Author
// token为空拒绝访问
String token = request.getHeaders().getFirst(AuthConstants.JWT_TOKEN_HEADER);
String token = request.getHeaders().getFirst(AuthConstants.AUTHORIZATION_KEY);
if (StrUtil.isBlank(token)) {
log.info("请求token为空拒绝访问path={}", path);
return Mono.just(new AuthorizationDecision(false));