什么是Api接口幂等?
大略来说Api接口幂等在有限的功夫内控制接口考察乞求,控制ip考察度数,不控制平台考察,都不妨拿到数据。一个接口不不妨反复表单提交,消费一次耗费一次。
用户场景:同一功夫反复提交屡次乞求。
什么是数据窜改?
api接口数据窜改,剧本文献,窜改接口参数举行效劳器数据夺取,重要的数据窜改会引导数据库宕机,步调软硬件解体。
想到这边都领会后盾api接口幂等多要害了吧。即日给大师讲非对称加密实行后盾接口api幂等。
实行思绪:jtw+ 考证标识+出面密钥+暂时功夫戳+寄存过时功夫+AES 实行加密算法token。
实行办法:1,用户登录胜利后,消费加密token寄存redis.
2,下次登录检查token 能否过时,过时请从新登录。
3,用户登录生存灵验期,不须要登录。(这边即是单点登录办法)
code中心实行类:
import io.jsonwebtoken.*;import org.slf4j.Logger;import org.slf4j.LoggerFactory;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 org.springframework.util.StringUtils;import javax.annotation.PostConstruct;import javax.servlet.http.HttpServletRequest;import java.util.*;import java.util.stream.Collectors;@Componentpublic class JWTTokenUtils {public static final String AUTHORIZATION_HEADER = "x-token";public static final String AUTHORIZATION_TOKEN = "x-token";private final Logger logger = LoggerFactory.getLogger(JWTTokenUtils.class);private static final String AUTHORITIES_KEY = "auth";private String secretKey; // 出面密钥private long tokenValidityInMilliseconds; // 作废日子private long tokenValidityInMillisecondsForRememberMe; // (记取我)作废日子@PostConstructpublic void init() {this.secretKey = "isoftstone.huwei";int secondIn1day = 1000 * 60 * 60 * 24;this.tokenValidityInMilliseconds = secondIn1day * 2L;this.tokenValidityInMillisecondsForRememberMe = secondIn1day * 7L;}// 创造Tokenpublic String createToken(Authentication authentication, Boolean rememberMe) {String authorities = authentication.getAuthorities().stream() // 获得用户的权力字符串,如 USER,ADMIN.map(GrantedAuthority::getAuthority).collect(Collectors.joining(","));long now = (new Date()).getTime(); // 获得暂时功夫戳Date validity; // 寄存过时功夫if (rememberMe) {validity = new Date(now + this.tokenValidityInMilliseconds);} else {validity = new Date(now + this.tokenValidityInMillisecondsForRememberMe);}return SysConst.SYS_COMPANY_HEAD+"."+ Jwts.builder() // 创造Token令牌.setSubject(authentication.getName()) // 树立面向用户.claim(AUTHORITIES_KEY, authorities) // 增添权力属性.setExpiration(validity) // 树立作废功夫.signWith(SignatureAlgorithm.HS512, secretKey) // 天生出面.compact();}// 获得用户权力public Authentication getAuthentication(String token) {logger.info("JWTTokenUtils Start Get User Auth");// 领会Token的payloadClaims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody();Collection<? extends GrantedAuthority> authorities = Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(",")) // 获得用户权力字符串.map(SimpleGrantedAuthority::new).collect(Collectors.toList()); // 将元素变换为GrantedAuthority接口汇合User principal = new User(claims.getSubject(), "", authorities);return new UsernamePasswordAuthenticationToken(principal, null, authorities);}/** * 领会token获得用户源代码 * @param token * @return */public String getAuthSubject(String token) {Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody();return claims.getSubject();}public String resolveToken(HttpServletRequest request){ String bearerToken = request.getHeader(AUTHORIZATION_HEADER); //从HTTP头部获得TOKEN if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(SysConst.SYS_COMPANY_HEAD)){ return bearerToken.substring(bearerToken.indexOf(".")+1, bearerToken.length()); //归来Token字符串,去除Bearer } String jwt = request.getParameter(AUTHORIZATION_TOKEN); //从乞求参数中获得TOKEN if (StringUtils.hasText(jwt) && jwt.startsWith(SysConst.SYS_COMPANY_HEAD)) { return jwt.substring(bearerToken.indexOf(".")+1, jwt.length()); } return null; }// 考证Token能否精确public boolean validateToken(String token) {try {Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token); // 经过密钥考证Tokenreturn true;} catch (MalformedJwtException e) { // JWT方法缺点logger.info("Invalid JWT token.");logger.trace("Invalid JWT token trace: {}", e);} catch (ExpiredJwtException e) { // JWT过时logger.info("Expired JWT token.");logger.trace("Expired JWT token trace: {}", e);} catch (UnsupportedJwtException e) { // 不扶助该JWTlogger.info("Unsupported JWT token.");logger.trace("Unsupported JWT token trace: {}", e);} catch (IllegalArgumentException e) { // 参数缺点特殊logger.info("JWT token compact of handler are invalid.");logger.trace("JWT token compact of handler are invalid trace: {}", e);}catch (SignatureException e) { // 出面特殊logger.info("Invalid JWT signature.");logger.trace("Invalid JWT signature trace: {}", e);}return false;}}redis写入缓存:
RedisModel model = new RedisModel(); model.setModelName(token); model.setModelKey("userInfo"); Map<String,Object> params = new HashMap<String,Object>(); params.put("userName", customerDto.getUsername()); CustomerVo customerVo = new CustomerVo(); customerVo.setEmail(customerDto.getEmail()); customerVo.setPhone(customerDto.getPhone()); CustomerVo userInfo = customerService.queryUserByUserName(customerVo); Map<String,Object> userToken = new HashMap<String,Object>(); userToken.put("userToken", token); userToken.put("userInfo", userInfo); model.setModelData(userToken); model.setTimeoutType("M"); model.setTimeout(redisTokenTimeOut); resultMap.setCode(CommonResultStatus.SUCCESS.getCode()); resultMap.setMessage(CommonResultStatus.SUCCESS.getMessage()); //写入为hash实业 redisTemplate.opsForHash().put(model.getModelName(), model.getModelKey(), model.getModelData()); redisTemplate.expire(model.getModelName(), model.getTimeout(), TimeUnit.MINUTES);@Configuration@EnableWebSecurity@EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter {public static final String AUTHORIZATION_HEADER = "x-token";//Authorization//承诺考察的路途private static final String***;] AUTH_WITHOUTLIST = {// -- swagger ui"/v2/api-docs", "/swagger-resources", "/swagger-resources/**", "/configuration/ui","/configuration/security", "/swagger-ui.html", "/webjars/**",// other public endpoints of your API may be appended to this array"/druid/**","/health","/info","/info/**",//druid sql 监听"/hystrix","/hystrix/**","/error","/loggers","/loggers/**","/service-registry/instance-status","/hystrix.stream","/turbine/**","/turbine.stream","/autoconfig","/archaius","/beans","/features","/configprops","/mappings","/auditevents","/env","/env/**","/metrics","/metrics/**","/trace","/trace/**", "/dump","/dump/**", "/jolokia/**","/info/**","/activiti/**", "/logfile/**", "/refresh","/flyway/**", "/liquibase/**","/heapdump","/heapdump/**","/v1/authcenter/login","/v1/authcenter/fiberhomeLogin","/v1/authcenter/registered",//登录URL"/v1/authcenter/queryAuthInfo",//鉴权URL"/u/sms/sendPhone","/citry/getChineseProvinces","/code/getCaptchaImage","/u/sms/forgetEmailPwd","/u/sms/sendEmail","/citry/getOtherCoutryList","/upload/pngDir/*","/job/getJobList","/u/sms/sendLoginEmail","/v1/authcenter/queryUserInfoByMap","/v1/authcenter/forgetPwd","/diagram-viwmer/**","/editor-marketing/**","/modeler.html","/actuator/health"};@Autowiredprivate SecurityUserDetailsService securityUserDetailsService;@Autowiredprivate AuthLogoutSuccessHandler authLogoutSuccessHandler;@Autowiredprivate JWTTokenUtils tokenProvider;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {//自设置获得用户消息树立暗号加密 和默许用DaoAuthenticationProvider加密任选auth.userDetailsService(securityUserDetailsService).passwordEncoder(passwordEncoder());}@Overrideprotected void configure(HttpSecurity http) throws Exception {// 摆设乞求考察战略// 封闭CSRF、CORShttp.cors().disable().csrf().disable()// 因为运用Token,以是不须要Session.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()// 考证Http乞求.authorizeRequests()// 承诺一切用户考察首页 与 登录.antMatchers(AUTH_WITHOUTLIST).permitAll()// 其它任何乞求都要过程认证经过.anyRequest().authenticated().and()// 用户页面须要用户权力// 树立登出.logout().logoutSuccessHandler(authLogoutSuccessHandler).permitAll();// 增添JWT filter 在http.addFilterBefore(new JwtAuthenticationTokenFilter(tokenProvider), UsernamePasswordAuthenticationFilter.class);}//确定能否有权力分三步 后盾security 仍旧对地方做了阻挡了,乞求头必需树立乞求参数参数1:确定token能否生存(security 已实行)2:token能否灵验(鉴于redis) 3:考察API能否有权力缓存构造:
***; "java.util.HashMap", { "userToken": "ISOFTSTONE.eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiI0MmRkMGJlZmQwNDg0MmMyODhiN2QxZjVkYTcwMWNjNiIsImF1dGgiOiJ1c2VyIiwiZXhwIjoxNjM1MjMyMzk4fQ.9VqMD0vyu-pe42moNd1QeNWP4KrBvvNYJKDQdQPDi_YKKXPG3l90dNn5wgK2rZXs471Pmeby-BdHPHd2-iNKfA", "userInfo": ***; "com.common.vo.CustomerVo", { "id": "42dd0befd04842c288b7d1f5da701cc6", "createTime": ***; "java.util.Date", "2021-06-10" ], "updateTime": ***; "java.util.Date", "2021-06-10" ], "deleted": 0, "phone": "13797004616", "password": "123456", "email": "sunlin@fiberhome.com", "status": %