yshop1.8.2移除idworker,移动端springsecuriry+jwt验证改进,明细可登陆后台查看

This commit is contained in:
hupeng
2020-01-13 13:31:10 +08:00
parent 3977f79185
commit 854cc843b3
62 changed files with 2165 additions and 2495 deletions

View File

@ -17,7 +17,6 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication
@EnableTransactionManagement
@MapperScan({"co.yixiang.modules.*.mapper"})
@ComponentScan(basePackages = {"co.yixiang", "org.n3r.idworker"})
public class ApiRun {
public static void main(String[] args) {

View File

@ -1,11 +1,15 @@
package co.yixiang.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
@ -29,13 +33,16 @@ public class ConfigurerAdapter implements WebMvcConfigurer {
@Value("${file.avatar}")
private String avatar;
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedHeaders("*")
.allowedOrigins("*")
.allowedMethods("GET","POST","PUT","DELETE");
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}

View File

@ -7,6 +7,7 @@ import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.http.HttpUtil;
import co.yixiang.annotation.AnonymousAccess;
import co.yixiang.aop.log.Log;
import co.yixiang.common.api.ApiResult;
import co.yixiang.common.web.controller.BaseController;
@ -77,6 +78,7 @@ public class StoreBargainController extends BaseController {
/**
* 砍价产品列表
*/
@AnonymousAccess
@GetMapping("/bargain/list")
@ApiOperation(value = "砍价产品列表",notes = "砍价产品列表",response = YxStoreBargainQueryVo.class)
public ApiResult<Object> getYxStoreBargainPageList(@RequestParam(value = "page", defaultValue = "1") int page,

View File

@ -6,6 +6,7 @@ import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.http.HttpUtil;
import co.yixiang.annotation.AnonymousAccess;
import co.yixiang.aop.log.Log;
import co.yixiang.common.api.ApiResult;
import co.yixiang.common.web.controller.BaseController;
@ -64,6 +65,7 @@ public class StoreCombinationController extends BaseController {
/**
* 拼团产品列表
*/
@AnonymousAccess
@GetMapping("/combination/list")
@ApiOperation(value = "拼团产品列表",notes = "拼团产品列表",response = YxStoreCombinationQueryVo.class)
public ApiResult<Object> getList(@RequestParam(value = "page",defaultValue = "1") int page,

View File

@ -3,6 +3,7 @@ package co.yixiang.modules.activity.web.controller;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import co.yixiang.annotation.AnonymousAccess;
import co.yixiang.common.api.ApiResult;
import co.yixiang.common.web.controller.BaseController;
import co.yixiang.modules.activity.service.YxStoreSeckillService;
@ -50,6 +51,7 @@ public class StoreSeckillController extends BaseController {
/**
* 秒杀产品列表
*/
@AnonymousAccess
@GetMapping("/seckill/list/{time}")
@ApiOperation(value = "秒杀产品列表", notes = "秒杀产品列表", response = YxStoreSeckillQueryVo.class)
public ApiResult<Object> getYxStoreSeckillPageList(@PathVariable String time,
@ -72,6 +74,7 @@ public class StoreSeckillController extends BaseController {
/**
* 根据id获取商品秒杀产品详情
*/
@AnonymousAccess
@GetMapping("/seckill/detail/{id}")
@ApiOperation(value = "获取YxStoreSeckill对象详情", notes = "查看商品秒杀产品表", response = YxStoreSeckillQueryVo.class)
public ApiResult<Object> getYxStoreSeckill(@PathVariable Integer id) throws Exception {
@ -82,6 +85,7 @@ public class StoreSeckillController extends BaseController {
/**
* 秒杀产品时间区间
*/
@AnonymousAccess
@GetMapping("/seckill/index")
@ApiOperation(value = "秒杀产品时间区间", notes = "秒杀产品时间区间", response = YxStoreSeckillQueryVo.class)
public ApiResult<Object> getYxStoreSeckillIndex() throws Exception {

View File

@ -2,6 +2,7 @@ package co.yixiang.modules.manage.web.controller;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import co.yixiang.annotation.AnonymousAccess;
import co.yixiang.common.api.ApiResult;
import co.yixiang.common.web.controller.BaseController;
import co.yixiang.modules.manage.service.YxExpressService;
@ -112,6 +113,7 @@ public class ShoperController extends BaseController {
/**
* 快递公司
*/
@AnonymousAccess
@GetMapping("/logistics")
@ApiOperation(value = "快递公司",notes = "快递公司")
public ApiResult<Object> express(){

View File

@ -72,7 +72,6 @@ import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import lombok.extern.slf4j.Slf4j;
import org.n3r.idworker.Sid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -172,8 +171,6 @@ public class YxStoreOrderServiceImpl extends BaseServiceImpl<YxStoreOrderMapper,
@Autowired
private AlipayService alipayService;
@Autowired
private Sid sid;
@Autowired
private MqProducer mqProducer;
@ -1341,7 +1338,7 @@ public class YxStoreOrderServiceImpl extends BaseServiceImpl<YxStoreOrderMapper,
if(payPrice <= 0) payPrice = 0d;
//生成分布式唯一值
String orderSn = sid.nextShort();
String orderSn = IdUtil.getSnowflake(0,0).nextIdStr();
//组合数据
YxStoreOrder storeOrder = new YxStoreOrder();
storeOrder.setUid(uid);
@ -1410,8 +1407,8 @@ public class YxStoreOrderServiceImpl extends BaseServiceImpl<YxStoreOrderMapper,
//使用MQ延时消息
mqProducer.sendMsg("yshop-topic",storeOrder.getId().toString());
log.info("投递延时订单id [{}]", storeOrder.getId());
//mqProducer.sendMsg("yshop-topic",storeOrder.getId().toString());
//log.info("投递延时订单id [{}]", storeOrder.getId());
return storeOrder;
}

View File

@ -1,15 +1,14 @@
package co.yixiang.modules.security.config;
import co.yixiang.modules.security.security.JwtAuthorizationTokenFilter;
import co.yixiang.modules.security.service.JwtUserDetailsService;
import co.yixiang.annotation.AnonymousAccess;
import co.yixiang.modules.security.security.JwtAccessDeniedHandler;
import co.yixiang.modules.security.security.JwtAuthenticationEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import co.yixiang.modules.security.security.TokenConfigurer;
import co.yixiang.modules.security.security.TokenProvider;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@ -19,136 +18,114 @@ import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @author hupeng
* @date 2020/01/12
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
private final TokenProvider tokenProvider;
private final CorsFilter corsFilter;
private final JwtAuthenticationEntryPoint authenticationErrorHandler;
private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
private final ApplicationContext applicationContext;
@Autowired
private JwtUserDetailsService jwtUserDetailsService;
/**
* 自定义基于JWT的安全过滤器
*/
@Autowired
JwtAuthorizationTokenFilter authenticationTokenFilter;
@Value("${jwt.header}")
private String tokenHeader;
@Value("${jwt.auth.path}")
private String loginPath;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(jwtUserDetailsService)
.passwordEncoder(passwordEncoderBean());
public SecurityConfig(TokenProvider tokenProvider, CorsFilter corsFilter, JwtAuthenticationEntryPoint authenticationErrorHandler, JwtAccessDeniedHandler jwtAccessDeniedHandler, ApplicationContext applicationContext) {
this.tokenProvider = tokenProvider;
this.corsFilter = corsFilter;
this.authenticationErrorHandler = authenticationErrorHandler;
this.jwtAccessDeniedHandler = jwtAccessDeniedHandler;
this.applicationContext = applicationContext;
}
@Bean
GrantedAuthorityDefaults grantedAuthorityDefaults() {
// Remove the ROLE_ prefix
// 去除 ROLE_ 前缀
return new GrantedAuthorityDefaults("");
}
@Bean
public PasswordEncoder passwordEncoderBean() {
public PasswordEncoder passwordEncoder() {
// 密码加密方式
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// 搜寻匿名标记 url @AnonymousAccess
Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = applicationContext.getBean(RequestMappingHandlerMapping.class).getHandlerMethods();
Set<String> anonymousUrls = new HashSet<>();
for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {
HandlerMethod handlerMethod = infoEntry.getValue();
AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);
if (null != anonymousAccess) {
anonymousUrls.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
}
}
httpSecurity
// 禁用 CSRF
.csrf().disable()
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
// 授权异常
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.exceptionHandling()
.authenticationEntryPoint(authenticationErrorHandler)
.accessDeniedHandler(jwtAccessDeniedHandler)
// 防止iframe 造成跨域
.and()
.headers()
.frameOptions()
.disable()
// 不创建会话
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
// 过滤请求
.and()
.authorizeRequests()
// 静态资源等等
.antMatchers(
HttpMethod.GET,
"/*.html",
"/**/*.html",
"/**/*.css",
"/**/*.js"
).anonymous()
.antMatchers( HttpMethod.POST,"/"+loginPath).anonymous()
.antMatchers( HttpMethod.POST,"/wxapp/auth").anonymous()
//首页
.antMatchers("/index").anonymous()
.antMatchers("/article/**").anonymous()
.antMatchers("/groom/list/*").anonymous()
.antMatchers("/search/keyword").anonymous()
//.antMatchers("/product/hot").anonymous()
.antMatchers("/products/**").anonymous()
.antMatchers("/product/hot").anonymous()
.antMatchers("/category").anonymous()
//.antMatchers("/coupons/**").anonymous()
.antMatchers("/image_base64").anonymous()
.antMatchers("/register/verify").anonymous()
.antMatchers("/register").anonymous()
.antMatchers("/user/activity").anonymous()
.antMatchers("/combination/list").anonymous()
.antMatchers("/webservice/**").anonymous()
//微信相关
.antMatchers("/wechat/config").anonymous()
.antMatchers("/wechat/auth").anonymous()
.antMatchers("/share").anonymous()
.antMatchers("/wechat/notify").anonymous()
.antMatchers("/notify/refund").anonymous()
.antMatchers("/wechat/serve").anonymous()
.antMatchers("/logistics").anonymous()
.antMatchers("/seckill/index").anonymous()
.antMatchers("/seckill/list/**").anonymous()
.antMatchers("/seckill/list/**").anonymous()
.antMatchers("/seckill/detail/*").anonymous()
.antMatchers("/bargain/list/**").anonymous()
// 支付宝回调
.antMatchers("/api/aliPay/return").anonymous()
.antMatchers("/api/aliPay/notify").anonymous()
// swagger start
.antMatchers("/swagger-ui.html").anonymous()
.antMatchers("/swagger-resources/**").anonymous()
.antMatchers("/webjars/**").anonymous()
.antMatchers("/*/api-docs").anonymous()
// swagger end
// 接口限流测试
.antMatchers("/test/**").anonymous()
"/**/*.js",
"/webSocket/**"
).permitAll()
// swagger 文档
.antMatchers("/swagger-ui.html").permitAll()
.antMatchers("/swagger-resources/**").permitAll()
.antMatchers("/webjars/**").permitAll()
.antMatchers("/*/api-docs").permitAll()
// 文件
.antMatchers("/avatar/**").anonymous()
.antMatchers("/file/**").anonymous()
.antMatchers("/avatar/**").permitAll()
.antMatchers("/file/**").permitAll()
// 阿里巴巴 druid
.antMatchers("/druid/**").permitAll()
// 放行OPTIONS请求
.antMatchers(HttpMethod.OPTIONS, "/**").anonymous()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/druid/**").anonymous()
// 自定义匿名访问所有url放行 允许匿名和带权限以及登录用户访问
.antMatchers(anonymousUrls.toArray(new String[0])).permitAll()
// 所有请求都需要认证
.anyRequest().authenticated()
// 防止iframe 造成跨域
.and().headers().frameOptions().disable();
.and().apply(securityConfigurerAdapter());
}
httpSecurity
.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
private TokenConfigurer securityConfigurerAdapter() {
return new TokenConfigurer(tokenProvider);
}
}

View File

@ -0,0 +1,35 @@
package co.yixiang.modules.security.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* @author hupeng
* @date 2020/01/12
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "jwt")
public class SecurityProperties {
/** Request Headers Authorization */
private String header;
/** 令牌前缀,最后留个空格 Bearer */
private String tokenStartWith;
/** 必须使用最少88位的Base64对该令牌进行编码 */
private String base64Secret;
/** 令牌过期时间 此处单位/毫秒 */
private Long tokenValidityInSeconds;
/** 在线用户 key根据 key 查询 redis 中在线用户的数据 */
private String onlineKey;
public String getTokenStartWith() {
return tokenStartWith + " ";
}
}

View File

@ -0,0 +1,469 @@
package co.yixiang.modules.security.rest;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import co.yixiang.annotation.AnonymousAccess;
import co.yixiang.aop.log.Log;
import co.yixiang.common.api.ApiCode;
import co.yixiang.common.api.ApiResult;
import co.yixiang.exception.ErrorRequestException;
import co.yixiang.modules.security.config.SecurityProperties;
import co.yixiang.modules.security.rest.param.RegParam;
import co.yixiang.modules.security.rest.param.VerityParam;
import co.yixiang.modules.security.security.TokenProvider;
import co.yixiang.modules.security.security.vo.AuthUser;
import co.yixiang.modules.security.security.vo.JwtUser;
import co.yixiang.modules.security.service.OnlineUserService;
import co.yixiang.modules.user.entity.YxUser;
import co.yixiang.modules.user.entity.YxWechatUser;
import co.yixiang.modules.user.service.YxUserService;
import co.yixiang.modules.user.service.YxWechatUserService;
import co.yixiang.modules.user.web.vo.YxUserQueryVo;
import co.yixiang.utils.OrderUtil;
import co.yixiang.utils.RedisUtil;
import co.yixiang.utils.RedisUtils;
import co.yixiang.utils.SecurityUtils;
import com.vdurmont.emoji.EmojiParser;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author hupeng
* @date 2020/01/12
*/
@Slf4j
@RestController
@Api(tags = "用户授权中心")
public class AuthController {
@Value("${single.login:false}")
private Boolean singleLogin;
private final SecurityProperties properties;
private final RedisUtils redisUtils;
private final UserDetailsService userDetailsService;
private final OnlineUserService onlineUserService;
private final TokenProvider tokenProvider;
private final AuthenticationManagerBuilder authenticationManagerBuilder;
private final YxUserService userService;
private final PasswordEncoder passwordEncoder;
private final WxMpService wxService;
private final YxWechatUserService wechatUserService;
private final WxMaService wxMaService;
public AuthController(SecurityProperties properties, RedisUtils redisUtils,
UserDetailsService userDetailsService,
OnlineUserService onlineUserService, TokenProvider tokenProvider,
AuthenticationManagerBuilder authenticationManagerBuilder,
YxUserService userService, PasswordEncoder passwordEncoder,
WxMpService wxService, YxWechatUserService wechatUserService,
WxMaService wxMaService) {
this.properties = properties;
this.redisUtils = redisUtils;
this.userDetailsService = userDetailsService;
this.onlineUserService = onlineUserService;
this.tokenProvider = tokenProvider;
this.authenticationManagerBuilder = authenticationManagerBuilder;
this.userService = userService;
this.passwordEncoder = passwordEncoder;
this.wxService = wxService;
this.wechatUserService = wechatUserService;
this.wxMaService = wxMaService;
}
@Log("H5用户登录")
@ApiOperation("H5登录授权")
@AnonymousAccess
@PostMapping(value = "/login")
public ApiResult<Map<String, String>> login(@Validated @RequestBody AuthUser authUser,
HttpServletRequest request) {
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(authUser.getUsername(), authUser.getPassword());
Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
// 生成令牌
String token = tokenProvider.createToken(authentication);
final JwtUser jwtUser = (JwtUser) authentication.getPrincipal();
// 保存在线信息
onlineUserService.save(jwtUser, token, request);
Date expiresTime = tokenProvider.getExpirationDateFromToken(token);
String expiresTimeStr = DateUtil.formatDateTime(expiresTime);
// 返回 token 与 用户信息
Map<String, Object> authInfo = new HashMap<String, Object>(2) {{
put("token", token);
put("expires_time", expiresTimeStr);
}};
if (singleLogin) {
//踢掉之前已经登录的token
onlineUserService.checkLoginOnUser(authUser.getUsername(), token);
}
// 返回 token
return ApiResult.ok(authInfo);
}
/**
* 微信公众号授权
*/
@AnonymousAccess
@GetMapping("/wechat/auth")
@ApiOperation(value = "微信公众号授权", notes = "微信公众号授权")
public ApiResult<Object> authLogin(@RequestParam(value = "code") String code,
@RequestParam(value = "spread") String spread,
HttpServletRequest request) {
try {
WxMpOAuth2AccessToken wxMpOAuth2AccessToken = wxService.oauth2getAccessToken(code);
WxMpUser wxMpUser = wxService.oauth2getUserInfo(wxMpOAuth2AccessToken, null);
String openid = wxMpUser.getOpenId();
YxWechatUser wechatUser = wechatUserService.getUserInfo(openid);
JwtUser jwtUser = null;
if (ObjectUtil.isNotNull(wechatUser)) {
YxUserQueryVo yxUserQueryVo = userService.getYxUserById(wechatUser.getUid());
if (ObjectUtil.isNotNull(yxUserQueryVo)) {
jwtUser = (JwtUser) userDetailsService.loadUserByUsername(wechatUser.getOpenid());
} else {
if (ObjectUtil.isNotNull(wechatUser)) {
wechatUserService.removeById(wechatUser.getUid());
}
if (ObjectUtil.isNotNull(yxUserQueryVo)) {
userService.removeById(yxUserQueryVo.getUid());
}
return ApiResult.fail(ApiCode.FAIL_AUTH, "授权失败");
}
} else {
//过滤掉表情
String nickname = EmojiParser.removeAllEmojis(wxMpUser.getNickname());
log.info("昵称:{}", nickname);
//用户保存
YxUser user = new YxUser();
user.setAccount(nickname);
user.setUsername(wxMpUser.getOpenId());
user.setPassword(passwordEncoder.encode("123456"));
user.setPwd(passwordEncoder.encode("123456"));
user.setPhone("");
user.setUserType("wechat");
user.setAddTime(OrderUtil.getSecondTimestampTwo());
user.setLastTime(OrderUtil.getSecondTimestampTwo());
user.setNickname(nickname);
user.setAvatar(wxMpUser.getHeadImgUrl());
user.setNowMoney(BigDecimal.ZERO);
user.setBrokeragePrice(BigDecimal.ZERO);
user.setIntegral(BigDecimal.ZERO);
userService.save(user);
//保存微信用户
YxWechatUser yxWechatUser = new YxWechatUser();
yxWechatUser.setAddTime(OrderUtil.getSecondTimestampTwo());
yxWechatUser.setNickname(nickname);
yxWechatUser.setOpenid(wxMpUser.getOpenId());
int sub = 0;
if (ObjectUtil.isNotNull(wxMpUser.getSubscribe()) && wxMpUser.getSubscribe()) sub = 1;
yxWechatUser.setSubscribe(sub);
yxWechatUser.setSex(wxMpUser.getSex());
yxWechatUser.setLanguage(wxMpUser.getLanguage());
yxWechatUser.setCity(wxMpUser.getCity());
yxWechatUser.setProvince(wxMpUser.getProvince());
yxWechatUser.setCountry(wxMpUser.getCountry());
yxWechatUser.setHeadimgurl(wxMpUser.getHeadImgUrl());
if (ObjectUtil.isNotNull(wxMpUser.getSubscribeTime())) {
yxWechatUser.setSubscribeTime(wxMpUser.getSubscribeTime().intValue());
}
if (StrUtil.isNotEmpty(wxMpUser.getUnionId())) {
yxWechatUser.setUnionid(wxMpUser.getUnionId());
}
if (StrUtil.isNotEmpty(wxMpUser.getRemark())) {
yxWechatUser.setUnionid(wxMpUser.getRemark());
}
if (ObjectUtil.isNotEmpty(wxMpUser.getGroupId())) {
yxWechatUser.setGroupid(wxMpUser.getGroupId());
}
yxWechatUser.setUid(user.getUid());
wechatUserService.save(yxWechatUser);
jwtUser = (JwtUser) userDetailsService.loadUserByUsername(wxMpUser.getOpenId());
}
//设置推广关系
if (StrUtil.isNotEmpty(spread) && !spread.equals("NaN")) {
//System.out.println("spread:"+spread);
userService.setSpread(Integer.valueOf(spread),
jwtUser.getId().intValue());
}
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(jwtUser.getUsername(),
"123456");
Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
// 生成令牌
String token = tokenProvider.createToken(authentication);
final JwtUser jwtUserT = (JwtUser) authentication.getPrincipal();
// 保存在线信息
onlineUserService.save(jwtUserT, token, request);
Date expiresTime = tokenProvider.getExpirationDateFromToken(token);
String expiresTimeStr = DateUtil.formatDateTime(expiresTime);
Map<String, String> map = new LinkedHashMap<>();
map.put("token", token);
map.put("expires_time", expiresTimeStr);
// 返回 token
return ApiResult.ok(map);
} catch (WxErrorException e) {
e.printStackTrace();
log.error(e.getMessage());
return ApiResult.fail("授权失败");
}
}
/**
* 小程序登陆接口
*/
@AnonymousAccess
@PostMapping("/wxapp/auth")
@ApiOperation(value = "小程序登陆", notes = "小程序登陆")
public ApiResult<Object> login(@RequestParam(value = "code") String code,
@RequestParam(value = "spread") String spread,
@RequestParam(value = "encryptedData") String encryptedData,
@RequestParam(value = "iv") String iv,
HttpServletRequest request) {
if (StringUtils.isBlank(code)) {
return ApiResult.fail("请传code");
}
try {
//读取redis配置
String appId = RedisUtil.get("wxapp_appId");
String secret = RedisUtil.get("wxapp_secret");
if (StrUtil.isBlank(appId) || StrUtil.isBlank(secret)) {
throw new ErrorRequestException("请先配置小程序");
}
WxMaDefaultConfigImpl wxMaConfig = new WxMaDefaultConfigImpl();
wxMaConfig.setAppid(appId);
wxMaConfig.setSecret(secret);
wxMaService.setWxMaConfig(wxMaConfig);
WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(code);
YxWechatUser wechatUser = wechatUserService.getUserInfo(session.getOpenid());
;
JwtUser jwtUser = null;
if (ObjectUtil.isNotNull(wechatUser)) {
YxUserQueryVo yxUserQueryVo = userService.getYxUserById(wechatUser.getUid());
if (ObjectUtil.isNotNull(yxUserQueryVo)) {
jwtUser = (JwtUser) userDetailsService.loadUserByUsername(wechatUser.getOpenid());
} else {
if (ObjectUtil.isNotNull(wechatUser)) {
wechatUserService.removeById(wechatUser.getUid());
}
if (ObjectUtil.isNotNull(yxUserQueryVo)) {
userService.removeById(yxUserQueryVo.getUid());
}
return ApiResult.fail(ApiCode.FAIL_AUTH, "授权失败");
}
} else {
WxMaUserInfo wxMpUser = wxMaService.getUserService()
.getUserInfo(session.getSessionKey(), encryptedData, iv);
//过滤掉表情
String nickname = EmojiParser.removeAllEmojis(wxMpUser.getNickName());
//用户保存
YxUser user = new YxUser();
user.setAccount(nickname);
user.setUsername(wxMpUser.getOpenId());
user.setPassword(passwordEncoder.encode("123456"));
user.setPwd(passwordEncoder.encode("123456"));
user.setPhone("");
user.setUserType("routine");
user.setAddTime(OrderUtil.getSecondTimestampTwo());
user.setLastTime(OrderUtil.getSecondTimestampTwo());
user.setNickname(nickname);
user.setAvatar(wxMpUser.getAvatarUrl());
user.setNowMoney(BigDecimal.ZERO);
user.setBrokeragePrice(BigDecimal.ZERO);
user.setIntegral(BigDecimal.ZERO);
userService.save(user);
//保存微信用户
YxWechatUser yxWechatUser = new YxWechatUser();
// System.out.println("wxMpUser:"+wxMpUser);
yxWechatUser.setAddTime(OrderUtil.getSecondTimestampTwo());
yxWechatUser.setNickname(nickname);
yxWechatUser.setRoutineOpenid(wxMpUser.getOpenId());
int sub = 0;
yxWechatUser.setSubscribe(sub);
yxWechatUser.setSex(Integer.valueOf(wxMpUser.getGender()));
yxWechatUser.setLanguage(wxMpUser.getLanguage());
yxWechatUser.setCity(wxMpUser.getCity());
yxWechatUser.setProvince(wxMpUser.getProvince());
yxWechatUser.setCountry(wxMpUser.getCountry());
yxWechatUser.setHeadimgurl(wxMpUser.getAvatarUrl());
if (StrUtil.isNotEmpty(wxMpUser.getUnionId())) {
yxWechatUser.setUnionid(wxMpUser.getUnionId());
}
yxWechatUser.setUid(user.getUid());
wechatUserService.save(yxWechatUser);
jwtUser = (JwtUser) userDetailsService.loadUserByUsername(wxMpUser.getOpenId());
}
//设置推广关系
if (StrUtil.isNotEmpty(spread)) {
userService.setSpread(Integer.valueOf(spread),
jwtUser.getId().intValue());
}
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(jwtUser.getUsername(),
"123456");
Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
// 生成令牌
String token = tokenProvider.createToken(authentication);
final JwtUser jwtUserT = (JwtUser) authentication.getPrincipal();
// 保存在线信息
onlineUserService.save(jwtUserT, token, request);
Date expiresTime = tokenProvider.getExpirationDateFromToken(token);
String expiresTimeStr = DateUtil.formatDateTime(expiresTime);
Map<String, String> map = new LinkedHashMap<>();
map.put("token", token);
map.put("expires_time", expiresTimeStr);
// 返回 token
return ApiResult.ok(map);
} catch (WxErrorException e) {
log.error(e.getMessage(), e);
return ApiResult.fail(e.toString());
}
}
@AnonymousAccess
@PostMapping("/register/verify")
@ApiOperation(value = "验证码发送", notes = "验证码发送")
public ApiResult<String> verify(@Validated @RequestBody VerityParam param) {
Boolean isTest = true;
YxUser yxUser = userService.findByName(param.getPhone());
if (param.getType().equals("register") && ObjectUtil.isNotNull(yxUser)) {
return ApiResult.fail("手机号已注册");
}
if (param.getType().equals("login") && ObjectUtil.isNull(yxUser)) {
return ApiResult.fail("账号不存在");
}
if (ObjectUtil.isNotNull(redisUtils.get("code_" + param.getPhone()))) {
return ApiResult.fail("10分钟内有效:" + redisUtils.get("code_" + param.getPhone()).toString());
}
String code = RandomUtil.randomNumbers(6);
redisUtils.set("code_" + param.getPhone(), code, 600L);
if (isTest) {
return ApiResult.fail("测试阶段验证码:" + code);
}
return ApiResult.ok("发送成功");
}
@AnonymousAccess
@PostMapping("/register")
@ApiOperation(value = "H5注册新用户", notes = "H5注册新用户")
public ApiResult<String> register(@Validated @RequestBody RegParam param) {
String code = redisUtils.get("code_" + param.getAccount()).toString();
if (StrUtil.isEmpty(code)) {
return ApiResult.fail("请先获取验证码");
}
if (!StrUtil.equals(code, param.getCaptcha())) {
return ApiResult.fail("验证码错误");
}
YxUser yxUser = userService.findByName(param.getAccount());
if (ObjectUtil.isNotNull(yxUser)) {
return ApiResult.fail("用户已存在");
}
YxUser user = new YxUser();
user.setAccount(param.getAccount());
user.setUsername(param.getAccount());
user.setPassword(passwordEncoder.encode(param.getPassword()));
user.setPwd(passwordEncoder.encode(param.getPassword()));
user.setPhone(param.getAccount());
user.setUserType("h5");
user.setAddTime(OrderUtil.getSecondTimestampTwo());
user.setLastTime(OrderUtil.getSecondTimestampTwo());
user.setNickname(param.getAccount());
user.setAvatar("https://image.dayouqiantu.cn/5dc2c7f3a104c.png");
user.setNowMoney(BigDecimal.ZERO);
user.setBrokeragePrice(BigDecimal.ZERO);
user.setIntegral(BigDecimal.ZERO);
userService.save(user);
return ApiResult.ok("注册成功");
}
@ApiOperation("获取用户信息")
@GetMapping(value = "/info")
public ApiResult<Object> getUserInfo() {
JwtUser jwtUser = (JwtUser) userDetailsService.loadUserByUsername(SecurityUtils.getUsername());
return ApiResult.ok(jwtUser);
}
@ApiOperation(value = "退出登录", notes = "退出登录")
@AnonymousAccess
@PostMapping(value = "/auth/logout")
public ApiResult<Object> logout(HttpServletRequest request) {
onlineUserService.logout(tokenProvider.getToken(request));
return ApiResult.ok("退出成功");
}
}

View File

@ -1,183 +0,0 @@
package co.yixiang.modules.security.rest;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import co.yixiang.aop.log.Log;
import co.yixiang.common.api.ApiResult;
import co.yixiang.common.web.controller.BaseController;
import co.yixiang.modules.monitor.service.RedisService;
import co.yixiang.modules.security.rest.param.RegParam;
import co.yixiang.modules.security.rest.param.VerityParam;
import co.yixiang.modules.security.security.AuthorizationUser;
import co.yixiang.modules.security.security.JwtUser;
import co.yixiang.modules.security.utils.JwtTokenUtil;
import co.yixiang.modules.user.entity.YxUser;
import co.yixiang.modules.user.service.YxUserService;
import co.yixiang.utils.EncryptUtils;
import co.yixiang.utils.OrderUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author hupeng
* @date 2019-10-01
* 授权、根据token获取用户详细信息
*/
@Slf4j
@RestController
@Api(value = "H5认证模块", tags = "H5认证模块", description = "H5认证模块")
public class AuthenticationController extends BaseController {
@Value("${jwt.header}")
private String tokenHeader;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
@Qualifier("jwtUserDetailsService")
private UserDetailsService userDetailsService;
@Autowired
private RedisService redisService;
@Autowired
private YxUserService userService;
/**
* 登录授权
* @param authorizationUser
* @return
*/
@Log("用户登录")
@PostMapping(value = "${jwt.auth.path}")
@ApiOperation(value = "用户登录",notes = "用户登录")
public ApiResult<Map<String,String>> login(@Validated @RequestBody AuthorizationUser authorizationUser){
final JwtUser jwtUser = (JwtUser) userDetailsService.loadUserByUsername(authorizationUser.getAccount());
if(!jwtUser.getPassword().equals(EncryptUtils.encryptPassword(authorizationUser.getPassword()))){
throw new AccountExpiredException("密码错误");
}
if(!jwtUser.isEnabled()){
throw new AccountExpiredException("账号已停用,请联系管理员");
}
//设置推广关系
if(StrUtil.isNotEmpty(authorizationUser.getSpread()) &&
!authorizationUser.getSpread().equals("NaN")){
userService.setSpread(Integer.valueOf(authorizationUser.getSpread()),
jwtUser.getId().intValue());
}
// 生成令牌
final String token = jwtTokenUtil.generateToken(jwtUser);
Date expiresTime = jwtTokenUtil.getExpirationDateFromToken(token);
String expiresTimeStr = DateUtil.formatDateTime(expiresTime);
Map<String,String> map = new LinkedHashMap<>();
map.put("token",token);
map.put("expires_time",expiresTimeStr);
// 返回 token
return ApiResult.ok(map);
}
@PostMapping("/register/verify")
@ApiOperation(value = "验证码发送",notes = "验证码发送")
public ApiResult<String> verify(@Validated @RequestBody VerityParam param){
Boolean isTest = true;
YxUser yxUser = userService.findByName(param.getPhone());
if(param.getType().equals("register") && ObjectUtil.isNotNull(yxUser)){
return ApiResult.fail("手机号已注册");
}
if(param.getType().equals("login") && ObjectUtil.isNull(yxUser)){
return ApiResult.fail("账号不存在");
}
if(StrUtil.isNotEmpty(redisService.getCodeVal("code_"+param.getPhone()))){
return ApiResult.fail("10分钟内有效:"+redisService.getCodeVal("code_"+param.getPhone()));
}
String code = RandomUtil.randomNumbers(6);
redisService.saveCode("code_"+param.getPhone(),code,600L);
if(isTest){
return ApiResult.fail("测试阶段验证码:"+code);
}
return ApiResult.ok("发送成功");
}
@PostMapping("/register")
@ApiOperation(value = "H5注册新用户",notes = "H5注册新用户")
public ApiResult<String> register(@Validated @RequestBody RegParam param){
String code = redisService.getCodeVal("code_"+param.getAccount());
if(StrUtil.isEmpty(code)){
return ApiResult.fail("请先获取验证码");
}
if(!StrUtil.equals(code,param.getCaptcha())){
return ApiResult.fail("验证码错误");
}
YxUser yxUser = userService.findByName(param.getAccount());
if(ObjectUtil.isNotNull(yxUser)){
return ApiResult.fail("用户已存在");
}
YxUser user = new YxUser();
user.setAccount(param.getAccount());
user.setUsername(param.getAccount());
user.setPassword(EncryptUtils.encryptPassword(param.getPassword()));
user.setPwd(EncryptUtils.encryptPassword(param.getPassword()));
user.setPhone(param.getAccount());
user.setUserType("h5");
user.setAddTime(OrderUtil.getSecondTimestampTwo());
user.setLastTime(OrderUtil.getSecondTimestampTwo());
user.setNickname(param.getAccount());
user.setAvatar("https://image.dayouqiantu.cn/5dc2c7f3a104c.png");
user.setNowMoney(BigDecimal.ZERO);
user.setBrokeragePrice(BigDecimal.ZERO);
user.setIntegral(BigDecimal.ZERO);
userService.save(user);
return ApiResult.ok("注册成功");
}
/**
* 退出登录
* @return
*/
@PostMapping(value = "/auth/logout")
@ApiOperation(value = "退出登录",notes = "退出登录")
public ApiResult logout(){
return ApiResult.ok("退出成功");
}
}

View File

@ -1,20 +0,0 @@
package co.yixiang.modules.security.security;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.io.Serializable;
/**
* @author Zheng Jie
* @date 2018-11-23
* 返回token
*/
@Getter
@AllArgsConstructor
public class AuthenticationInfo implements Serializable {
private final String token;
private final JwtUser user;
}

View File

@ -1,17 +0,0 @@
package co.yixiang.modules.security.security;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* @author Zheng Jie
* @date 2019-6-5 17:29:57
*/
@Data
@AllArgsConstructor
public class ImgResult {
private String img;
private String uuid;
}

View File

@ -0,0 +1,23 @@
package co.yixiang.modules.security.security;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author hupeng
* @date 2020/01/12
*/
@Component
public class JwtAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
//将调用此方法发送403 Forbidden响应
response.sendError(HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage());
}
}

View File

@ -7,20 +7,19 @@ import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Serializable;
/**
* @author hupeng
* @date 2020/01/12
*/
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {
private static final long serialVersionUID = -8970718410437077606L;
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {
/**
* 当用户尝试访问安全的REST资源而不提供任何凭据时将调用此方法发送401 响应
*/
//将调用此方法发送401 响应
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException==null?"Unauthorized":authException.getMessage());
}
}

View File

@ -1,67 +0,0 @@
package co.yixiang.modules.security.security;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import co.yixiang.modules.security.utils.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
@Component
public class JwtAuthorizationTokenFilter extends OncePerRequestFilter {
private final UserDetailsService userDetailsService;
private final JwtTokenUtil jwtTokenUtil;
private final String tokenHeader;
public JwtAuthorizationTokenFilter(@Qualifier("jwtUserDetailsService") UserDetailsService userDetailsService, JwtTokenUtil jwtTokenUtil, @Value("${jwt.header}") String tokenHeader) {
this.userDetailsService = userDetailsService;
this.jwtTokenUtil = jwtTokenUtil;
this.tokenHeader = tokenHeader;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
final String requestHeader = request.getHeader(this.tokenHeader);
String username = null;
String authToken = null;
if (requestHeader != null && requestHeader.startsWith("Bearer ")) {
authToken = requestHeader.substring(7);
try {
username = jwtTokenUtil.getUsernameFromToken(authToken);
} catch (ExpiredJwtException e) {
log.error(e.getMessage());
}
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
// It is not compelling necessary to load the use details from the database. You could also store the information
// in the token and read it from it. It's up to you ;)
JwtUser userDetails = (JwtUser)this.userDetailsService.loadUserByUsername(username);
// For simple validation it is completely sufficient to just check the token integrity. You don't have to call
// the database compellingly. Again it's up to you ;)
if (jwtTokenUtil.validateToken(authToken, userDetails)) {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
chain.doFilter(request, response);
}
}

View File

@ -0,0 +1,25 @@
package co.yixiang.modules.security.security;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
/**
* @author hupeng
* @date 2020/01/12
*/
public class TokenConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
private final TokenProvider tokenProvider;
public TokenConfigurer(TokenProvider tokenProvider){
this.tokenProvider = tokenProvider;
}
@Override
public void configure(HttpSecurity http) {
TokenFilter customFilter = new TokenFilter(tokenProvider);
http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
}
}

View File

@ -0,0 +1,78 @@
package co.yixiang.modules.security.security;
import co.yixiang.modules.security.config.SecurityProperties;
import co.yixiang.modules.security.security.vo.JwtUser;
import co.yixiang.modules.security.security.vo.OnlineUser;
import co.yixiang.modules.security.service.OnlineUserService;
import co.yixiang.utils.SpringContextHolder;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
/**
* @author hupeng
* @date 2020/01/12
*/
@Slf4j
public class TokenFilter extends GenericFilterBean {
private final TokenProvider tokenProvider;
TokenFilter(TokenProvider tokenProvider) {
this.tokenProvider = tokenProvider;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String token = resolveToken(httpServletRequest);
String requestRri = httpServletRequest.getRequestURI();
// 验证 token 是否存在
OnlineUser onlineUser = null;
try {
SecurityProperties properties = SpringContextHolder.getBean(SecurityProperties.class);
OnlineUserService onlineUserService = SpringContextHolder.getBean(OnlineUserService.class);
onlineUser = onlineUserService.getOne(properties.getOnlineKey() + token);
} catch (ExpiredJwtException e) {
log.error(e.getMessage());
}
if (onlineUser != null && StringUtils.hasText(token) && tokenProvider.validateToken(token)) {
//Authentication authentication = tokenProvider.getAuthentication(token);
//SecurityContextHolder.getContext().setAuthentication(authentication);
JwtUser userDetails = new JwtUser(onlineUser.getId(),
onlineUser.getUserName(),onlineUser.getNickName(),"","","",
new ArrayList<>(),true,0);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails, null,
new ArrayList<>());
//authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
log.debug("set Authentication to security context for '{}', uri: {}", authentication.getName(), requestRri);
} else {
log.debug("no valid JWT token found, uri: {}", requestRri);
}
filterChain.doFilter(servletRequest, servletResponse);
}
private String resolveToken(HttpServletRequest request) {
SecurityProperties properties = SpringContextHolder.getBean(SecurityProperties.class);
String bearerToken = request.getHeader(properties.getHeader());
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(properties.getTokenStartWith())) {
return bearerToken.substring(7);
}
return null;
}
}

View File

@ -0,0 +1,116 @@
package co.yixiang.modules.security.security;
import co.yixiang.modules.security.config.SecurityProperties;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.security.Key;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.stream.Collectors;
/**
* @author hupeng
* @date 2020/01/12
*/
@Slf4j
@Component
public class TokenProvider implements InitializingBean {
private final SecurityProperties properties;
private static final String AUTHORITIES_KEY = "auth";
private Key key;
public TokenProvider(SecurityProperties properties) {
this.properties = properties;
}
@Override
public void afterPropertiesSet() {
byte[] keyBytes = Decoders.BASE64.decode(properties.getBase64Secret());
this.key = Keys.hmacShaKeyFor(keyBytes);
}
public String createToken(Authentication authentication) {
String authorities = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(","));
long now = (new Date()).getTime();
Date validity = new Date(now + properties.getTokenValidityInSeconds());
return Jwts.builder()
.setSubject(authentication.getName())
.claim(AUTHORITIES_KEY, authorities)
.signWith(key, SignatureAlgorithm.HS512)
.setExpiration(validity)
.compact();
}
Authentication getAuthentication(String token) {
Claims claims = Jwts.parser()
.setSigningKey(key)
.parseClaimsJws(token)
.getBody();
Collection<? extends GrantedAuthority> authorities =
Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
User principal = new User(claims.getSubject(), "", authorities);
return new UsernamePasswordAuthenticationToken(principal, token, authorities);
}
public Date getExpirationDateFromToken(String token) {
return getAllClaimsFromToken(token).getExpiration();
}
private Claims getAllClaimsFromToken(String token) {
return Jwts.parser()
.setSigningKey(key)
.parseClaimsJws(token)
.getBody();
}
boolean validateToken(String authToken) {
try {
Jwts.parser().setSigningKey(key).parseClaimsJws(authToken);
return true;
} catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) {
log.info("Invalid JWT signature.");
e.printStackTrace();
} catch (ExpiredJwtException e) {
log.info("Expired JWT token.");
e.printStackTrace();
} catch (UnsupportedJwtException e) {
log.info("Unsupported JWT token.");
e.printStackTrace();
} catch (IllegalArgumentException e) {
log.info("JWT token compact of handler are invalid.");
e.printStackTrace();
}
return false;
}
public String getToken(HttpServletRequest request){
final String requestHeader = request.getHeader(properties.getHeader());
if (requestHeader != null && requestHeader.startsWith(properties.getTokenStartWith())) {
return requestHeader.substring(7);
}
return null;
}
}

View File

@ -1,4 +1,4 @@
package co.yixiang.modules.security.security;
package co.yixiang.modules.security.security.vo;
import lombok.Getter;
import lombok.Setter;
@ -6,15 +6,15 @@ import lombok.Setter;
import javax.validation.constraints.NotBlank;
/**
* @author Zheng Jie
* @date 2018-11-30
* @author hupeng
* @date 2020/01/12
*/
@Getter
@Setter
public class AuthorizationUser {
public class AuthUser {
@NotBlank
private String account;
private String username;
@NotBlank
private String password;
@ -27,6 +27,6 @@ public class AuthorizationUser {
@Override
public String toString() {
return "{username=" + account + ", password= ******}";
return "{username=" + username + ", password= ******}";
}
}

View File

@ -1,8 +1,9 @@
package co.yixiang.modules.security.security;
package co.yixiang.modules.security.security.vo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
@ -13,17 +14,19 @@ import java.util.stream.Collectors;
/**
* @author hupeng
* @since 2019-10-16
* @date 2020/01/12
*/
@Getter
@AllArgsConstructor
public class JwtUser implements UserDetails {
@JsonIgnore
private final Long id;
private final String username;
private final String nickName;
@JsonIgnore
private final String password;
@ -36,12 +39,11 @@ public class JwtUser implements UserDetails {
@JsonIgnore
private final Collection<GrantedAuthority> authorities;
private final boolean enabled;
private Boolean status;
private Integer createTime;
private Integer addTime;
@JsonIgnore
@Override
@ -69,8 +71,10 @@ public class JwtUser implements UserDetails {
@Override
public boolean isEnabled() {
return status;
return enabled;
}
public Collection getRoles() {
return authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet());
}
}

View File

@ -0,0 +1,34 @@
package co.yixiang.modules.security.security.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* @author hupeng
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OnlineUser {
private Long id;
private String userName;
private String nickName;
private String browser;
private String ip;
private String address;
private String key;
private Date loginTime;
}

View File

@ -3,13 +3,15 @@ package co.yixiang.modules.security.service;
import co.yixiang.modules.user.entity.YxUser;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
@Service
//@CacheConfig(cacheNames = "role")
public class JwtPermissionService {
@ -18,13 +20,16 @@ public class JwtPermissionService {
* @param user
* @return
*/
//@Cacheable(key = "'loadPermissionByUser:' + #p0.username")
public Collection<GrantedAuthority> mapToGrantedAuthorities(YxUser user) {
System.out.println("--------------------loadPermissionByUser:" + user.getUsername() + "---------------------");
//Set<Role> roles = roleRepository.findByUsers_Id(user.getId());
List<String> list = new ArrayList<>();
list.add("yshop");
return new ArrayList<>();
return list.stream().map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,129 @@
package co.yixiang.modules.security.service;
import co.yixiang.modules.security.config.SecurityProperties;
import co.yixiang.modules.security.security.vo.JwtUser;
import co.yixiang.modules.security.security.vo.OnlineUser;
import co.yixiang.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
/**
* @author hupeng
* @Date 2020/01/12
*/
@Service
@Slf4j
public class OnlineUserService {
private final SecurityProperties properties;
private RedisUtils redisUtils;
public OnlineUserService(SecurityProperties properties, RedisUtils redisUtils) {
this.properties = properties;
this.redisUtils = redisUtils;
}
/**
* 保存在线用户信息
* @param jwtUser /
* @param token /
* @param request /
*/
public void save(JwtUser jwtUser, String token, HttpServletRequest request){
String ip = StringUtils.getIp(request);
String browser = StringUtils.getBrowser(request);
String address = StringUtils.getCityInfo(ip);
OnlineUser onlineUser = null;
try {
onlineUser = new OnlineUser(jwtUser.getId(),jwtUser.getUsername(), jwtUser.getNickName(), browser , ip, address, EncryptUtils.desEncrypt(token), new Date());
} catch (Exception e) {
e.printStackTrace();
}
redisUtils.set(properties.getOnlineKey() + token, onlineUser, properties.getTokenValidityInSeconds()/1000);
}
/**
* 查询全部数据,不分页
* @param filter /
* @return /
*/
public List<OnlineUser> getAll(String filter){
List<String> keys = redisUtils.scan(properties.getOnlineKey() + "*");
Collections.reverse(keys);
List<OnlineUser> onlineUsers = new ArrayList<>();
for (String key : keys) {
OnlineUser onlineUser = (OnlineUser) redisUtils.get(key);
if(StringUtils.isNotBlank(filter)){
if(onlineUser.toString().contains(filter)){
onlineUsers.add(onlineUser);
}
} else {
onlineUsers.add(onlineUser);
}
}
onlineUsers.sort((o1, o2) -> o2.getLoginTime().compareTo(o1.getLoginTime()));
return onlineUsers;
}
/**
* 踢出用户
* @param key /
* @throws Exception /
*/
public void kickOut(String key) throws Exception {
key = properties.getOnlineKey() + EncryptUtils.desDecrypt(key);
redisUtils.del(key);
}
/**
* 退出登录
* @param token /
*/
public void logout(String token) {
String key = properties.getOnlineKey() + token;
redisUtils.del(key);
}
/**
* 查询用户
* @param key /
* @return /
*/
public OnlineUser getOne(String key) {
return (OnlineUser)redisUtils.get(key);
}
/**
* 检测用户是否在之前已经登录,已经登录踢下线
* @param userName 用户名
*/
public void checkLoginOnUser(String userName, String igoreToken){
List<OnlineUser> onlineUsers = getAll(userName);
if(onlineUsers ==null || onlineUsers.isEmpty()){
return;
}
for(OnlineUser onlineUser:onlineUsers){
if(onlineUser.getUserName().equals(userName)){
try {
String token =EncryptUtils.desDecrypt(onlineUser.getKey());
if(StringUtils.isNotBlank(igoreToken)&&!igoreToken.equals(token)){
this.kickOut(onlineUser.getKey());
}else if(StringUtils.isBlank(igoreToken)){
this.kickOut(onlineUser.getKey());
}
} catch (Exception e) {
log.error("checkUser is error",e);
}
}
}
}
}

View File

@ -1,47 +1,53 @@
package co.yixiang.modules.security.service;
import co.yixiang.exception.BadRequestException;
import co.yixiang.modules.security.security.JwtUser;
import co.yixiang.modules.security.security.vo.JwtUser;
import co.yixiang.modules.user.entity.YxUser;
import co.yixiang.modules.user.service.YxUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Optional;
/**
* @author hupeng
* @since 2019-10-16
* @date 2020/01/12
*/
@Service
@Service("userDetailsService")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class JwtUserDetailsService implements UserDetailsService {
public class UserDetailsServiceImpl implements UserDetailsService {
private final YxUserService userService;
private final JwtPermissionService permissionService;
@Autowired
private YxUserService yxUserService;
@Autowired
private JwtPermissionService permissionService;
public UserDetailsServiceImpl(YxUserService userService,JwtPermissionService permissionService) {
this.userService = userService;
this.permissionService = permissionService;
}
@Override
public UserDetails loadUserByUsername(String username){
System.out.println("username2:"+username);
YxUser user = yxUserService.findByName(username);
YxUser user = userService.findByName(username);
if (user == null) {
throw new BadRequestException(HttpStatus.UNAUTHORIZED,"账号不存在");
throw new BadRequestException("账号不存在");
} else {
if (!user.getStatus()) {
throw new BadRequestException("账号未激活");
}
return createJwtUser(user);
}
}
public UserDetails createJwtUser(YxUser user) {
private UserDetails createJwtUser(YxUser user) {
return new JwtUser(
user.getUid().longValue(),
Long.valueOf(user.getUid()),
user.getUsername(),
user.getNickname(),
user.getPassword(),
user.getAvatar(),
user.getPhone(),

View File

@ -1,123 +0,0 @@
package co.yixiang.modules.security.utils;
import co.yixiang.modules.security.security.JwtUser;
import io.jsonwebtoken.*;
import io.jsonwebtoken.impl.DefaultClock;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
@Component
public class JwtTokenUtil implements Serializable {
private static final long serialVersionUID = -3301605591108950415L;
private Clock clock = DefaultClock.INSTANCE;
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private Long expiration;
@Value("${jwt.header}")
private String tokenHeader;
public String getUsernameFromToken(String token) {
return getClaimFromToken(token, Claims::getSubject);
}
public Date getIssuedAtDateFromToken(String token) {
return getClaimFromToken(token, Claims::getIssuedAt);
}
public Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration);
}
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims);
}
private Claims getAllClaimsFromToken(String token) {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(clock.now());
}
private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) {
return (lastPasswordReset != null && created.before(lastPasswordReset));
}
private Boolean ignoreTokenExpiration(String token) {
// here you specify tokens, for that the expiration is ignored
return false;
}
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return doGenerateToken(claims, userDetails.getUsername());
}
private String doGenerateToken(Map<String, Object> claims, String subject) {
final Date createdDate = clock.now();
final Date expirationDate = calculateExpirationDate(createdDate);
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(createdDate)
.setExpiration(expirationDate)
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) {
final Date created = getIssuedAtDateFromToken(token);
return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset)
&& (!isTokenExpired(token) || ignoreTokenExpiration(token));
}
public String refreshToken(String token) {
final Date createdDate = clock.now();
final Date expirationDate = calculateExpirationDate(createdDate);
final Claims claims = getAllClaimsFromToken(token);
claims.setIssuedAt(createdDate);
claims.setExpiration(expirationDate);
return Jwts.builder()
.setClaims(claims)
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
public Boolean validateToken(String token, UserDetails userDetails) {
JwtUser user = (JwtUser) userDetails;
final Date created = getIssuedAtDateFromToken(token);
// final Date expiration = getExpirationDateFromToken(token);
// 如果token存在且token创建日期 > 最后修改密码的日期 则代表token有效
// return (!isTokenExpired(token)
// && !isCreatedBeforeLastPasswordReset(created, user.getLastPasswordResetDate())
// );
return !isTokenExpired(token);
}
private Date calculateExpirationDate(Date createdDate) {
return new Date(createdDate.getTime() + expiration);
}
}

View File

@ -1,199 +0,0 @@
package co.yixiang.modules.security.utils;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Random;
/**
* @author https://blog.csdn.net/ruixue0117/article/details/22829557
* @date 2019-6-20 17:28:53
*/
public class VerifyCodeUtils{
//使用到Algerian字体系统里没有的话需要安装字体字体只显示大写去掉了1,0,i,o几个容易混淆的字符
public static final String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
private static Random random = new Random();
/**
* 使用系统默认字符源生成验证码
* @param verifySize 验证码长度
* @return
*/
public static String generateVerifyCode(int verifySize){
return generateVerifyCode(verifySize, VERIFY_CODES);
}
/**
* 使用指定源生成验证码
* @param verifySize 验证码长度
* @param sources 验证码字符源
* @return
*/
public static String generateVerifyCode(int verifySize, String sources){
if(sources == null || sources.length() == 0){
sources = VERIFY_CODES;
}
int codesLen = sources.length();
Random rand = new Random(System.currentTimeMillis());
StringBuilder verifyCode = new StringBuilder(verifySize);
for(int i = 0; i < verifySize; i++){
verifyCode.append(sources.charAt(rand.nextInt(codesLen-1)));
}
return verifyCode.toString();
}
/**
* 输出指定验证码图片流
* @param w
* @param h
* @param os
* @param code
* @throws IOException
*/
public static void outputImage(int w, int h, OutputStream os, String code) throws IOException{
int verifySize = code.length();
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Random rand = new Random();
Graphics2D g2 = image.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
Color[] colors = new Color[5];
Color[] colorSpaces = new Color[] { Color.WHITE, Color.CYAN,
Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE,
Color.PINK, Color.YELLOW };
float[] fractions = new float[colors.length];
for(int i = 0; i < colors.length; i++){
colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];
fractions[i] = rand.nextFloat();
}
Arrays.sort(fractions);
g2.setColor(Color.GRAY);// 设置边框色
g2.fillRect(0, 0, w, h);
Color c = getRandColor(200, 250);
g2.setColor(c);// 设置背景色
g2.fillRect(0, 2, w, h-4);
//绘制干扰线
Random random = new Random();
g2.setColor(getRandColor(160, 200));// 设置线条的颜色
for (int i = 0; i < 20; i++) {
int x = random.nextInt(w - 1);
int y = random.nextInt(h - 1);
int xl = random.nextInt(6) + 1;
int yl = random.nextInt(12) + 1;
g2.drawLine(x, y, x + xl + 40, y + yl + 20);
}
// 添加噪点
float yawpRate = 0.05f;// 噪声率
int area = (int) (yawpRate * w * h);
for (int i = 0; i < area; i++) {
int x = random.nextInt(w);
int y = random.nextInt(h);
int rgb = getRandomIntColor();
image.setRGB(x, y, rgb);
}
shear(g2, w, h, c);// 使图片扭曲
g2.setColor(getRandColor(100, 160));
int fontSize = h-4;
Font font = new Font("Algerian", Font.ITALIC, fontSize);
g2.setFont(font);
char[] chars = code.toCharArray();
for(int i = 0; i < verifySize; i++){
AffineTransform affine = new AffineTransform();
affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize/2, h/2);
g2.setTransform(affine);
g2.drawChars(chars, i, 1, ((w-10) / verifySize) * i + 5, h/2 + fontSize/2 - 10);
}
g2.dispose();
ImageIO.write(image, "jpg", os);
}
private static Color getRandColor(int fc, int bc) {
if (fc > 255)
fc = 255;
if (bc > 255)
bc = 255;
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}
private static int getRandomIntColor() {
int[] rgb = getRandomRgb();
int color = 0;
for (int c : rgb) {
color = color << 8;
color = color | c;
}
return color;
}
private static int[] getRandomRgb() {
int[] rgb = new int[3];
for (int i = 0; i < 3; i++) {
rgb[i] = random.nextInt(255);
}
return rgb;
}
private static void shear(Graphics g, int w1, int h1, Color color) {
shearX(g, w1, h1, color);
shearY(g, w1, h1, color);
}
private static void shearX(Graphics g, int w1, int h1, Color color) {
int period = random.nextInt(2);
boolean borderGap = true;
int frames = 1;
int phase = random.nextInt(2);
for (int i = 0; i < h1; i++) {
double d = (double) (period >> 1)
* Math.sin((double) i / (double) period
+ (6.2831853071795862D * (double) phase)
/ (double) frames);
g.copyArea(0, i, w1, 1, (int) d, 0);
if (borderGap) {
g.setColor(color);
g.drawLine((int) d, i, 0, i);
g.drawLine((int) d + w1, i, w1, i);
}
}
}
private static void shearY(Graphics g, int w1, int h1, Color color) {
int period = random.nextInt(40) + 10; // 50;
boolean borderGap = true;
int frames = 20;
int phase = 7;
for (int i = 0; i < w1; i++) {
double d = (double) (period >> 1)
* Math.sin((double) i / (double) period
+ (6.2831853071795862D * (double) phase)
/ (double) frames);
g.copyArea(i, 0, 1, h1, 0, (int) d);
if (borderGap) {
g.setColor(color);
g.drawLine(i, (int) d, i, 0);
g.drawLine(i, (int) d + h1, i, h1);
}
}
}
}

View File

@ -1,5 +1,6 @@
package co.yixiang.modules.shop.web.controller;
import co.yixiang.annotation.AnonymousAccess;
import co.yixiang.common.api.ApiResult;
import co.yixiang.common.web.controller.BaseController;
import co.yixiang.common.web.vo.Paging;
@ -33,6 +34,7 @@ public class ArticleController extends BaseController {
/**
* 获取文章文章详情
*/
@AnonymousAccess
@GetMapping("/details/{id}")
@ApiOperation(value = "文章详情",notes = "文章详情",response = YxArticleQueryVo.class)
public ApiResult<YxArticleQueryVo> getYxArticle(@PathVariable Integer id) throws Exception{
@ -44,6 +46,7 @@ public class ArticleController extends BaseController {
/**
* 文章列表
*/
@AnonymousAccess
@GetMapping("/list")
@ApiOperation(value = "文章列表",notes = "文章列表",response = YxArticleQueryVo.class)
public ApiResult<Paging<YxArticleQueryVo>> getYxArticlePageList(

View File

@ -1,5 +1,6 @@
package co.yixiang.modules.shop.web.controller;
import co.yixiang.annotation.AnonymousAccess;
import co.yixiang.common.api.ApiResult;
import co.yixiang.modules.shop.service.YxStoreProductService;
import co.yixiang.modules.shop.service.YxSystemConfigService;
@ -34,6 +35,7 @@ public class IndexController {
@AnonymousAccess
@GetMapping("/index")
@ApiOperation(value = "首页数据",notes = "首页数据")
public ApiResult<Map<String,Object>> index(){
@ -66,6 +68,7 @@ public class IndexController {
return ApiResult.ok(map);
}
@AnonymousAccess
@GetMapping("/search/keyword")
@ApiOperation(value = "热门搜索关键字获取",notes = "热门搜索关键字获取")
public ApiResult<List<String>> search(){
@ -78,6 +81,7 @@ public class IndexController {
return ApiResult.ok(stringList);
}
@AnonymousAccess
@PostMapping("/image_base64")
@ApiOperation(value = "获取图片base64",notes = "获取图片base64")
public ApiResult<List<String>> imageBase64(){

View File

@ -1,5 +1,6 @@
package co.yixiang.modules.shop.web.controller;
import co.yixiang.annotation.AnonymousAccess;
import co.yixiang.common.api.ApiResult;
import co.yixiang.common.web.controller.BaseController;
import co.yixiang.common.web.vo.Paging;
@ -32,6 +33,7 @@ public class StoreCategoryController extends BaseController {
/**
* 商品分类列表
*/
@AnonymousAccess
@GetMapping("/category")
@ApiOperation(value = "商品分类列表",notes = "商品分类列表")
public ApiResult<Paging<YxStoreCategoryQueryVo>> getYxStoreCategoryPageList(){

View File

@ -1,5 +1,6 @@
package co.yixiang.modules.shop.web.controller;
import co.yixiang.annotation.AnonymousAccess;
import co.yixiang.aop.log.Log;
import co.yixiang.common.api.ApiResult;
import co.yixiang.common.web.controller.BaseController;
@ -45,6 +46,7 @@ public class StoreProductController extends BaseController {
/**
* 获取首页更多产品
*/
@AnonymousAccess
@GetMapping("/groom/list/{type}")
@ApiOperation(value = "获取首页更多产品",notes = "获取首页更多产品")
public ApiResult<Map<String,Object>> moreGoodsList(@PathVariable Integer type){
@ -66,6 +68,7 @@ public class StoreProductController extends BaseController {
/**
* 获取首页更多产品
*/
@AnonymousAccess
@GetMapping("/products")
@ApiOperation(value = "商品列表",notes = "商品列表")
public ApiResult<List<YxStoreProductQueryVo>> goodsList(YxStoreProductQueryParam productQueryParam){
@ -76,6 +79,7 @@ public class StoreProductController extends BaseController {
/**
* 为你推荐
*/
@AnonymousAccess
@GetMapping("/product/hot")
@ApiOperation(value = "为你推荐",notes = "为你推荐")
public ApiResult<List<YxStoreProductQueryVo>> productRecommend(

View File

@ -1,5 +1,6 @@
package co.yixiang.modules.user.web.controller;
import co.yixiang.annotation.AnonymousAccess;
import co.yixiang.aop.log.Log;
import co.yixiang.common.api.ApiResult;
import co.yixiang.common.web.controller.BaseController;
@ -134,6 +135,7 @@ public class UserController extends BaseController {
/**
* 获取活动状态
*/
@AnonymousAccess
@GetMapping("/user/activity")
@ApiOperation(value = "获取活动状态",notes = "获取活动状态")
public ApiResult<Object> activity(){

View File

@ -3,14 +3,13 @@ package co.yixiang.modules.wechat.web.controller;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import co.yixiang.annotation.AnonymousAccess;
import co.yixiang.common.api.ApiCode;
import co.yixiang.common.api.ApiResult;
import co.yixiang.common.web.controller.BaseController;
import co.yixiang.modules.order.entity.YxStoreOrder;
import co.yixiang.modules.order.service.YxStoreOrderService;
import co.yixiang.modules.order.web.vo.YxStoreOrderQueryVo;
import co.yixiang.modules.security.security.JwtUser;
import co.yixiang.modules.security.utils.JwtTokenUtil;
import co.yixiang.modules.shop.service.YxSystemConfigService;
import co.yixiang.modules.user.entity.YxUser;
import co.yixiang.modules.user.entity.YxWechatUser;
@ -69,17 +68,11 @@ public class WechatController extends BaseController {
private final WxMpMessageRouter messageRouter;
private final YxSystemConfigService systemConfigService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
@Qualifier("jwtUserDetailsService")
private UserDetailsService userDetailsService;
/**
* 微信分享配置
*/
@AnonymousAccess
@GetMapping("/share")
@ApiOperation(value = "微信分享配置",notes = "微信分享配置")
public ApiResult<Object> share() {
@ -95,131 +88,19 @@ public class WechatController extends BaseController {
/**
* jssdk配置
*/
@AnonymousAccess
@GetMapping("/wechat/config")
@ApiOperation(value = "jssdk配置",notes = "jssdk配置")
public ApiResult<Object> jsConfig(@RequestParam(value = "url") String url) throws WxErrorException {
return ApiResult.ok(wxService.createJsapiSignature(url));
}
/**
* 微信授权
*/
@GetMapping("/wechat/auth")
@ApiOperation(value = "微信授权",notes = "微信授权")
public ApiResult<Object> authLogin(@RequestParam(value = "code") String code,
@RequestParam(value = "spread") String spread) {
try {
WxMpOAuth2AccessToken wxMpOAuth2AccessToken = wxService.oauth2getAccessToken(code);
WxMpUser wxMpUser = wxService.oauth2getUserInfo(wxMpOAuth2AccessToken, null);
String openid = wxMpUser.getOpenId();
YxWechatUser wechatUser = wechatUserService.getUserInfo(openid);
JwtUser jwtUser = null;
if(ObjectUtil.isNotNull(wechatUser)){
YxUserQueryVo yxUserQueryVo = userService.getYxUserById(wechatUser.getUid());
if(ObjectUtil.isNotNull(yxUserQueryVo)){
jwtUser = (JwtUser) userDetailsService.loadUserByUsername(wechatUser.getOpenid());
}else{
if(ObjectUtil.isNotNull(wechatUser)){
wechatUserService.removeById(wechatUser.getUid());
}
if(ObjectUtil.isNotNull(yxUserQueryVo)){
userService.removeById(yxUserQueryVo.getUid());
}
return ApiResult.fail(ApiCode.FAIL_AUTH,"授权失败");
}
}else{
//过滤掉表情
String nickname = EmojiParser.removeAllEmojis(wxMpUser.getNickname());
log.info("昵称:{}",nickname);
//用户保存
YxUser user = new YxUser();
user.setAccount(nickname);
user.setUsername(wxMpUser.getOpenId());
user.setPassword(EncryptUtils.encryptPassword("123456"));
user.setPwd(EncryptUtils.encryptPassword("123456"));
user.setPhone("");
user.setUserType("wechat");
user.setAddTime(OrderUtil.getSecondTimestampTwo());
user.setLastTime(OrderUtil.getSecondTimestampTwo());
user.setNickname(nickname);
user.setAvatar(wxMpUser.getHeadImgUrl());
user.setNowMoney(BigDecimal.ZERO);
user.setBrokeragePrice(BigDecimal.ZERO);
user.setIntegral(BigDecimal.ZERO);
userService.save(user);
//保存微信用户
YxWechatUser yxWechatUser = new YxWechatUser();
yxWechatUser.setAddTime(OrderUtil.getSecondTimestampTwo());
yxWechatUser.setNickname(nickname);
yxWechatUser.setOpenid(wxMpUser.getOpenId());
int sub = 0;
if(ObjectUtil.isNotNull(wxMpUser.getSubscribe()) && wxMpUser.getSubscribe()) sub =1;
yxWechatUser.setSubscribe(sub);
yxWechatUser.setSex(wxMpUser.getSex());
yxWechatUser.setLanguage(wxMpUser.getLanguage());
yxWechatUser.setCity(wxMpUser.getCity());
yxWechatUser.setProvince(wxMpUser.getProvince());
yxWechatUser.setCountry(wxMpUser.getCountry());
yxWechatUser.setHeadimgurl(wxMpUser.getHeadImgUrl());
if(ObjectUtil.isNotNull(wxMpUser.getSubscribeTime())){
yxWechatUser.setSubscribeTime(wxMpUser.getSubscribeTime().intValue());
}
if(StrUtil.isNotEmpty(wxMpUser.getUnionId())){
yxWechatUser.setUnionid(wxMpUser.getUnionId());
}
if(StrUtil.isNotEmpty(wxMpUser.getRemark())){
yxWechatUser.setUnionid(wxMpUser.getRemark());
}
if(ObjectUtil.isNotEmpty(wxMpUser.getGroupId())){
yxWechatUser.setGroupid(wxMpUser.getGroupId());
}
yxWechatUser.setUid(user.getUid());
wechatUserService.save(yxWechatUser);
jwtUser = (JwtUser) userDetailsService.loadUserByUsername(wxMpUser.getOpenId());
}
//设置推广关系
if(StrUtil.isNotEmpty(spread) && !spread.equals("NaN")){
//System.out.println("spread:"+spread);
userService.setSpread(Integer.valueOf(spread),
jwtUser.getId().intValue());
}
// 生成令牌
final String token = jwtTokenUtil.generateToken(jwtUser);
Date expiresTime = jwtTokenUtil.getExpirationDateFromToken(token);
String expiresTimeStr = DateUtil.formatDateTime(expiresTime);
Map<String,String> map = new LinkedHashMap<>();
map.put("token",token);
map.put("expires_time",expiresTimeStr);
// 返回 token
return ApiResult.ok(map);
} catch (WxErrorException e) {
e.printStackTrace();
log.error(e.getMessage());
return ApiResult.fail("授权失败");
}
// return ApiResult.ok(wxService.createJsapiSignature(url));
}
/**
* 微信支付回调
*/
@AnonymousAccess
@PostMapping("/wechat/notify")
@ApiOperation(value = "微信支付回调",notes = "微信支付回调")
public String notify(@RequestBody String xmlData) {
@ -247,6 +128,7 @@ public class WechatController extends BaseController {
* @return
* @throws WxPayException
*/
@AnonymousAccess
@ApiOperation(value = "退款回调通知处理",notes = "退款回调通知处理")
@PostMapping("/notify/refund")
public String parseRefundNotifyResult(@RequestBody String xmlData) {
@ -275,6 +157,7 @@ public class WechatController extends BaseController {
/**
* 微信验证消息
*/
@AnonymousAccess
@GetMapping("/wechat/serve")
@ApiOperation(value = "微信验证消息",notes = "微信验证消息")
public String authGet(@RequestParam(name = "signature", required = false) String signature,
@ -290,7 +173,9 @@ public class WechatController extends BaseController {
}
@AnonymousAccess
@PostMapping("/wechat/serve")
@ApiOperation(value = "微信获取消息",notes = "微信获取消息")
public void post(@RequestBody String requestBody,
@RequestParam("signature") String signature,
@RequestParam("timestamp") String timestamp,

View File

@ -1,45 +1,13 @@
package co.yixiang.modules.wechat.web.controller;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import co.yixiang.common.api.ApiCode;
import co.yixiang.common.api.ApiResult;
import co.yixiang.exception.ErrorRequestException;
import co.yixiang.modules.security.security.JwtUser;
import co.yixiang.modules.security.utils.JwtTokenUtil;
import co.yixiang.modules.user.entity.YxUser;
import co.yixiang.modules.user.entity.YxWechatUser;
import co.yixiang.modules.user.service.YxUserService;
import co.yixiang.modules.user.service.YxWechatUserService;
import co.yixiang.modules.user.web.vo.YxUserQueryVo;
import co.yixiang.utils.EncryptUtils;
import co.yixiang.utils.OrderUtil;
import co.yixiang.utils.RedisUtil;
import com.vdurmont.emoji.EmojiParser;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 微信小程序用户接口
*
@ -49,132 +17,11 @@ import java.util.Map;
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Api(value = "微信小程序", tags = "微信小程序", description = "微信小程序")
public class WxMaUserController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final WxMaService wxMaService;
private final YxWechatUserService wechatUserService;
private final YxUserService userService;
private final JwtTokenUtil jwtTokenUtil;
@Autowired
@Qualifier("jwtUserDetailsService")
private UserDetailsService userDetailsService;
/**
* 小程序登陆接口
*/
@PostMapping("/wxapp/auth")
@ApiOperation(value = "小程序登陆",notes = "小程序登陆")
public ApiResult<Object> login(@RequestParam(value = "code") String code,
@RequestParam(value = "spread") String spread,
@RequestParam(value = "encryptedData") String encryptedData,
@RequestParam(value = "iv") String iv ) {
if (StringUtils.isBlank(code)) {
return ApiResult.fail("请传code");
}
try {
//读取redis配置
String appId = RedisUtil.get("wxapp_appId");
String secret = RedisUtil.get("wxapp_secret");
if(StrUtil.isBlank(appId) || StrUtil.isBlank(secret)){
throw new ErrorRequestException("请先配置小程序");
}
WxMaDefaultConfigImpl wxMaConfig = new WxMaDefaultConfigImpl();
wxMaConfig.setAppid(appId);
wxMaConfig.setSecret(secret);
wxMaService.setWxMaConfig(wxMaConfig);
WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(code);
YxWechatUser wechatUser = wechatUserService.getUserInfo(session.getOpenid());;
JwtUser jwtUser = null;
if(ObjectUtil.isNotNull(wechatUser)){
YxUserQueryVo yxUserQueryVo = userService.getYxUserById(wechatUser.getUid());
if(ObjectUtil.isNotNull(yxUserQueryVo)){
jwtUser = (JwtUser) userDetailsService.loadUserByUsername(wechatUser.getOpenid());
}else{
if(ObjectUtil.isNotNull(wechatUser)){
wechatUserService.removeById(wechatUser.getUid());
}
if(ObjectUtil.isNotNull(yxUserQueryVo)){
userService.removeById(yxUserQueryVo.getUid());
}
return ApiResult.fail(ApiCode.FAIL_AUTH,"授权失败");
}
}else{
WxMaUserInfo wxMpUser = wxMaService.getUserService()
.getUserInfo(session.getSessionKey(), encryptedData, iv);
//过滤掉表情
String nickname = EmojiParser.removeAllEmojis(wxMpUser.getNickName());
//用户保存
YxUser user = new YxUser();
user.setAccount(nickname);
user.setUsername(wxMpUser.getOpenId());
user.setPassword(EncryptUtils.encryptPassword("123456"));
user.setPwd(EncryptUtils.encryptPassword("123456"));
user.setPhone("");
user.setUserType("routine");
user.setAddTime(OrderUtil.getSecondTimestampTwo());
user.setLastTime(OrderUtil.getSecondTimestampTwo());
user.setNickname(nickname);
user.setAvatar(wxMpUser.getAvatarUrl());
user.setNowMoney(BigDecimal.ZERO);
user.setBrokeragePrice(BigDecimal.ZERO);
user.setIntegral(BigDecimal.ZERO);
userService.save(user);
//保存微信用户
YxWechatUser yxWechatUser = new YxWechatUser();
// System.out.println("wxMpUser:"+wxMpUser);
yxWechatUser.setAddTime(OrderUtil.getSecondTimestampTwo());
yxWechatUser.setNickname(nickname);
yxWechatUser.setRoutineOpenid(wxMpUser.getOpenId());
int sub = 0;
yxWechatUser.setSubscribe(sub);
yxWechatUser.setSex(Integer.valueOf(wxMpUser.getGender()));
yxWechatUser.setLanguage(wxMpUser.getLanguage());
yxWechatUser.setCity(wxMpUser.getCity());
yxWechatUser.setProvince(wxMpUser.getProvince());
yxWechatUser.setCountry(wxMpUser.getCountry());
yxWechatUser.setHeadimgurl(wxMpUser.getAvatarUrl());
if(StrUtil.isNotEmpty(wxMpUser.getUnionId())){
yxWechatUser.setUnionid(wxMpUser.getUnionId());
}
yxWechatUser.setUid(user.getUid());
wechatUserService.save(yxWechatUser);
jwtUser = (JwtUser) userDetailsService.loadUserByUsername(wxMpUser.getOpenId());
}
//设置推广关系
if(StrUtil.isNotEmpty(spread)){
//System.out.println("spread:"+spread);
userService.setSpread(Integer.valueOf(spread),
jwtUser.getId().intValue());
}
// 生成令牌
final String token = jwtTokenUtil.generateToken(jwtUser);
Date expiresTime = jwtTokenUtil.getExpirationDateFromToken(token);
String expiresTimeStr = DateUtil.formatDateTime(expiresTime);
Map<String,String> map = new LinkedHashMap<>();
map.put("token",token);
map.put("expires_time",expiresTimeStr);
// 返回 token
return ApiResult.ok(map);
} catch (WxErrorException e) {
this.logger.error(e.getMessage(), e);
return ApiResult.fail(e.toString());
}
}
// /**
// * <pre>
@ -182,7 +29,7 @@ public class WxMaUserController {
// * </pre>
// */
// @GetMapping("/phone")
// public String phone(@PathVariable String appid, String sessionKey, String signature,
// public String phone(String sessionKey, String signature,
// String rawData, String encryptedData, String iv) {
//
// // 用户信息校验
@ -196,4 +43,6 @@ public class WxMaUserController {
// return JsonUtils.toJson(phoneNoInfo);
// }
}

View File

@ -51,21 +51,19 @@ spring:
#连接超时时间
timeout: 5000
#jwt
#jwt
jwt:
header: Authorization
secret: JBqNQX7HD9xhwHP7
# 令牌前缀
token-start-with: Bearer
# token 过期时间 6个小时
expiration: 210000000
# 必须使用最少88位的Base64对该令牌进行编码
base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI=
# 令牌过期时间 此处单位/毫秒 默认4小时可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html
token-validity-in-seconds: 14400000
# 在线用户key
online-key: online-token
auth:
# 授权路径
path: /login
# 获取用户信息
account: /info
online-key: m-online-token
#是否开启 swagger-ui

View File

@ -55,18 +55,15 @@ spring:
#jwt
jwt:
header: Authorization
secret: JBqNQX7HD9xhwHP7YSHOP
# 令牌前缀
token-start-with: Bearer
# token 过期时间 2个小时
expiration: 7200000
# 必须使用最少88位的Base64对该令牌进行编码
base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI=
# 令牌过期时间 此处单位/毫秒 默认2小时可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html
token-validity-in-seconds: 7200000
# 在线用户key
online-key: online-token
auth:
# 授权路径
path: /login
# 获取用户信息
account: /info
online-key: m-online-token
#是否允许生成代码生产环境设置为false
generator: