Commit 03c8043f authored by gary's avatar gary

1、滴滴权限整合

parent 681b1d24
package pwc.taxtech.atms.common;
import pwc.taxtech.atms.security.DDUserInfo;
import java.util.Optional;
public interface AuthUserHelper {
......@@ -12,4 +14,6 @@ public interface AuthUserHelper {
String getClientIp();
DDUserInfo getDDUserInfo();
}
\ No newline at end of file
......@@ -14,8 +14,10 @@ import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import pwc.taxtech.atms.dao.UserMapper;
import pwc.taxtech.atms.exception.ApplicationException;
import pwc.taxtech.atms.security.DDUserInfo;
import pwc.taxtech.atms.security.JwtUser;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Optional;
......@@ -25,7 +27,7 @@ public class AuthUserHelperImpl implements AuditorAware<String>, AuthUserHelper
@Autowired(required = false)
private HttpServletRequest request;
@Autowired
@Resource
private UserMapper userMapper;
/*
......@@ -111,4 +113,21 @@ public class AuthUserHelperImpl implements AuditorAware<String>, AuthUserHelper
public String getClientIp() {
return Lang.getIP(request);
}
@Override
public DDUserInfo getDDUserInfo(){
SecurityContext context = SecurityContextHolder.getContext();
if (context == null) {
throw new ApplicationException("security context is null");
}
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
throw new ApplicationException("authentication failed");
}
JwtUser jwtUser = (JwtUser) authentication.getPrincipal();
if (jwtUser == null) {
return null;
}
return (DDUserInfo)jwtUser.getClientUserInfo();
}
}
......@@ -13,6 +13,7 @@ public class AtmsTokenDto {
private String user_name;
private String vat_api_host;
private String version;
private String ticket;
public String getAccess_token() {
return access_token;
......@@ -110,6 +111,14 @@ public class AtmsTokenDto {
this.version = version;
}
public String getTicket() {
return ticket;
}
public void setTicket(String ticket) {
this.ticket = ticket;
}
@Override
public String toString() {
return "CookieModel [access_token=" + access_token + ", token_type=" + token_type + ", expires_in=" + expires_in
......
......@@ -6,6 +6,10 @@ public class LoginInputDto {
private String password;
private String ticket;
private Integer type;
public String getEmail() {
return email;
}
......@@ -22,5 +26,19 @@ public class LoginInputDto {
this.password = password;
}
public String getTicket() {
return ticket;
}
public void setTicket(String ticket) {
this.ticket = ticket;
}
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
}
package pwc.taxtech.atms.security;
import com.alibaba.fastjson.annotation.JSONField;
/**
* @Auther: Gary J Li
* @Date: 05/03/2019 18:25
* @Description:
*/
public class DDUserInfo {
private int uid;
private String phone;
@JSONField(name = "username_zh")
private String username_zh;
private String email;
private String username;
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getUsername_zh() {
return username_zh;
}
public void setUsername_zh(String username_zh) {
this.username_zh = username_zh;
}
}
package pwc.taxtech.atms.security;
import com.alibaba.fastjson.annotation.JSONField;
/**
* @Auther: Gary J Li
* @Date: 05/03/2019 18:25
* @Description:
*/
public class DDUserInfoRes {
private int errno;
@JSONField(name = "data")
private DDUserInfo ddUserInfo;
private String errmsg;
public int getErrno() {
return errno;
}
public void setErrno(int errno) {
this.errno = errno;
}
public DDUserInfo getDdUserInfo() {
return ddUserInfo;
}
public void setDdUserInfo(DDUserInfo ddUserInfo) {
this.ddUserInfo = ddUserInfo;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
}
package pwc.taxtech.atms.security;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.impl.DefaultClaims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
......@@ -8,14 +10,18 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import pwc.taxtech.atms.common.util.HttpUtil;
import pwc.taxtech.atms.dto.AtmsTokenDto;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.Map;
public class JwtAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
......@@ -23,13 +29,20 @@ public class JwtAuthenticationFilter extends AbstractAuthenticationProcessingFil
private Integer jwtExpireSecond;
@Value("${jwt.refreshSecond}")
private Integer jwtRefreshSecond;
@Value("${get_user_info_url}")
private String getUserInfoUrl;
@Value("${app_id}")
private String appId;
@Autowired
private JwtUtil jwtUtil;
@Value("${check_ticket}")
private Boolean checkTicket;
public JwtAuthenticationFilter() {
super("/**");
}
@Override
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
String header = request.getHeader("Authorization");
return (header != null && (header.startsWith("bearer ") || header.startsWith("Bearer ")));
......@@ -53,7 +66,32 @@ public class JwtAuthenticationFilter extends AbstractAuthenticationProcessingFil
setDetails(request, authRequest);
return getAuthenticationManager().authenticate(authRequest);
Authentication authResult = getAuthenticationManager().authenticate(authRequest);
if (checkTicket) {
Cookie[] cookies = request.getCookies();
String ticket = "";
try {
for (Cookie cookie : cookies) {
if ("ddTicket".equals(cookie.getName())) {
ticket = cookie.getValue();
break;
}
}
JSONObject object;
String ddResp = HttpUtil.post(getUserInfoUrl + "check_ticket", "ticket=" + ticket + "&app_id=" + appId, "application/x-www-form-urlencoded", "UTF-8", 10000, 10000);
object = JSONObject.parseObject(ddResp);
Map<String, Object> res = object.getInnerMap();
int code = (int) res.get("errno");
if (code != 0) {
logger.warn(String.format("DD Ticket Check Failed:[%s]", object.toJSONString()));
return null;
}
logger.debug("ddTicket校验CODE:"+code);
} catch (Exception e) {
logger.error(String.format("调用DD获取用户信息失败:[%s]", e.getMessage()), e);
}
}
return authResult;
}
protected void setDetails(HttpServletRequest request,
......@@ -75,7 +113,7 @@ public class JwtAuthenticationFilter extends AbstractAuthenticationProcessingFil
DefaultClaims claims = jwtUser.getDefaultClaims();
if (claims.getExpiration().getTime() - System.currentTimeMillis() <= jwtRefreshSecond * 1000) {
String newToken = jwtUtil.generateToken(jwtUser.getUsername(), jwtUser.getDatabaseUsername(),
jwtUser.getUserid());
jwtUser.getUserid(),jwtUser.getTicket());
response.setHeader("Access-Control-Expose-Headers", "refreshToken");
response.setHeader("refreshToken", newToken);
logger.debug("refreshToken: " + newToken);
......
......@@ -8,20 +8,30 @@ import org.springframework.security.core.userdetails.UserDetails;
public class JwtUser implements UserDetails {
private static final long serialVersionUId = 1L;
private final String userid;
/** 登录名, 大小写不限,可以是全大写或全小写 */
private final String username;
/** 数据库用户名, 比如Admin */
private final String databaseUsername;
private final String ticket;
private Object clientUserInfo;
private final Collection<? extends GrantedAuthority> authorities;
private DefaultClaims defaultClaims;
public JwtUser(String userid, String username, String databaseUsername,
public JwtUser(String userid, String username, String databaseUsername,String ticket,Object clientUserInfo,
DefaultClaims defaultClaims, Collection<? extends GrantedAuthority> authorities) {
this.userid = userid;
this.username = username;
this.databaseUsername = databaseUsername;
this.ticket = ticket;
this.clientUserInfo = clientUserInfo;
this.authorities = authorities;
this.defaultClaims = defaultClaims;
}
......@@ -61,6 +71,18 @@ public class JwtUser implements UserDetails {
return true;
}
public String getTicket() {
return ticket;
}
public static long getSerialVersionUId() {
return serialVersionUId;
}
public Object getClientUserInfo() {
return clientUserInfo;
}
public String getUserid() {
return userid;
}
......
......@@ -3,7 +3,9 @@ package pwc.taxtech.atms.security;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.*;
import org.nutz.lang.Times;
import org.slf4j.Logger;
......@@ -20,6 +22,7 @@ import io.jsonwebtoken.impl.DefaultJws;
import io.jsonwebtoken.lang.Assert;
import pwc.taxtech.atms.common.AtmsApiSettings;
import pwc.taxtech.atms.common.CommonUtils;
import pwc.taxtech.atms.common.util.HttpUtil;
@Component
public class JwtUtil implements InitializingBean {
......@@ -31,6 +34,14 @@ public class JwtUtil implements InitializingBean {
private JwtAuthenticationService jwtAuthenticationService;
@Value("${jwt.expireSecond}")
private Integer jwtExpireSecond;
@Value("${get_user_info_url}")
private String getUserInfoUrl;
@Value("${app_id}")
private String appId;
@Value("${app_key}")
private String appKey;
@Value("${check_ticket}")
private Boolean checkTicket;
@Override
public void afterPropertiesSet() throws Exception {
......@@ -50,9 +61,6 @@ public class JwtUtil implements InitializingBean {
@SuppressWarnings({ "unchecked", "rawtypes" })
public JwtUser parseToken(String token) {
if (StringUtils.hasText(jwtPowerToken) && jwtPowerToken.equals(token)) {
return new JwtUser("test_userid", "admin", "Admin", null, getAuthorities());
}
JwtParser parser = Jwts.parser().setSigningKey(jwtBase64Secret);
Jwt jwt = parser.parseClaimsJws(token);
DefaultJws<DefaultClaims> defaultJws = (DefaultJws<DefaultClaims>) jwt;
......@@ -60,8 +68,25 @@ public class JwtUtil implements InitializingBean {
String databaseUsername = String.valueOf(defaultClaims.get("databaseUsername"));
String username = String.valueOf(defaultClaims.get("username"));
String userid = String.valueOf(defaultClaims.get("userid"));
String ticket = "";
JSONObject object;
Object userInfo = null;
if(checkTicket){
ticket = String.valueOf(defaultClaims.get("ticket"));
try {
String response = HttpUtil.post(getUserInfoUrl+"get_user_by_ticket", "ticket=" + ticket + "&app_id=" + appId, "application/x-www-form-urlencoded", "UTF-8", 10000, 10000);
object = JSONObject.parseObject(response);
Map<String, Object> res = object.getInnerMap();
userInfo = res.get("data");
} catch (Exception e) {
logger.error(String.format("调用DD获取用户信息失败:[%s]", e.getMessage()), e);
}
}
if (StringUtils.hasText(jwtPowerToken) && jwtPowerToken.equals(token)) {
return new JwtUser("test_userid", "admin", "Admin", ticket, userInfo, null, getAuthorities());
}
// 原版 UserDetails return new JwtUser(userid, username, databaseUsername, defaultClaims, getAuthorities());
return new JwtUser(userid, username, databaseUsername, defaultClaims, getAuthorities(userid));
return new JwtUser(userid, username, databaseUsername, ticket, userInfo, defaultClaims, getAuthorities(userid));
}
private List<SimpleGrantedAuthority> getAuthorities() {
......@@ -91,7 +116,7 @@ public class JwtUtil implements InitializingBean {
* 用户Id
* @return
*/
public String generateToken(String username, String databaseUsername, String userid) {
public String generateToken(String username, String databaseUsername, String userid,String ticket) {
// sub: 该JWT所面向的用户
// iss: 该JWT的签发者
// iat(issued at): 在什么时候签发的token
......@@ -115,6 +140,7 @@ public class JwtUtil implements InitializingBean {
jwtBuilder.claim("username", username);
jwtBuilder.claim("databaseUsername", databaseUsername);
jwtBuilder.claim("userid", userid);
jwtBuilder.claim("ticket", ticket);
// 设置body.username为数据库用户名
jwtBuilder.signWith(SignatureAlgorithm.HS512, jwtBase64Secret);
return jwtBuilder.compact();
......
......@@ -121,13 +121,16 @@ public class MenuServiceImpl {
permissionExample.createCriteria().andIdIn(permissionIds);
List<String> menuIds = permissionMapper.selectByExample(permissionExample)
.stream().map(Permission::getMenuId).collect(Collectors.toList());
// 数据问题,,暂时用这种蠢办法
// admin权限暂时不做控制
menuIds.add("91223c21-c15a-4882-89cc-42f3807ec9e3");
menuIds.add("9bf855fb-6b44-49cd-b95b-41a6a9a8c098");
menuIds.add("F9A18F3A-7E39-4661-BA00-F149710577C3");
menuIds.add("F9A18F3A-7E39-4661-BA00-F149710577C4");
menuIds.add("F9A18F3A-7E39-4661-BA00-F149710577C7");
// 这里的权限之后需要在数据库中加上对应的权限数据
menuIds.add("6b404066-2200-4d11-9436-d0870dfd3188");
menuIds.add("6b404066-2200-4d11-9436-d0870dfd3189");
menuIds.add("5bdbc9a7-197b-43cc-b0e6-3f50e41b13eb");
menuIds.add("5bdbc9a7-197b-43cc-b0e6-3f50e41b13ec");
menuIds.add("5bdbc9a7-197b-43cc-b0e6-3f50e41b13eg");
......
package pwc.taxtech.atms.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.BooleanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -19,6 +20,7 @@ import pwc.taxtech.atms.common.OperationModule;
import pwc.taxtech.atms.common.UserLoginType;
import pwc.taxtech.atms.common.UserStatus;
import pwc.taxtech.atms.common.message.UserMessage;
import pwc.taxtech.atms.common.util.HttpUtil;
import pwc.taxtech.atms.constant.DimensionConstant;
import pwc.taxtech.atms.constant.PermissionCode;
import pwc.taxtech.atms.constant.PermissionUrl;
......@@ -52,15 +54,9 @@ import pwc.taxtech.atms.dto.user.WebUserDto;
import pwc.taxtech.atms.entity.*;
import pwc.taxtech.atms.entity.UserRoleExample.Criteria;
import pwc.taxtech.atms.exception.ApplicationException;
import pwc.taxtech.atms.security.AtmsPasswordEncoder;
import pwc.taxtech.atms.security.JwtAuthenticationService;
import pwc.taxtech.atms.security.JwtUtil;
import pwc.taxtech.atms.security.LdapAuthenticationProvider;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import pwc.taxtech.atms.security.*;
import java.util.*;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.toList;
......@@ -110,6 +106,18 @@ public class UserServiceImpl extends AbstractService {
@Value("${api.url}")
private String apiUrl;
@Value("${get_user_info_url}")
private String getUserInfoUrl;
@Value("${app_id}")
private String appId;
@Value("${app_key}")
private String appKey;
@Value("${check_ticket}")
private Boolean checkTicket;
public UserPermissionDto getUserPermission(String userName) {
User user = userMapper.selectByUserNameIgnoreCase(userName);
if (user == null) {
......@@ -368,6 +376,9 @@ public class UserServiceImpl extends AbstractService {
public OperationResultDto<LoginOutputDto> login(LoginInputDto input) {
// return dummyLogin(input);
if(input.getType() == 1){
return loginByDDTicket(input);
}
return doLogin(input);
}
......@@ -375,8 +386,10 @@ public class UserServiceImpl extends AbstractService {
logger.debug("doLogin start");
Assert.notNull(input, "Null input");
final String inputLoginName = input.getEmail();
final String ticket = input.getTicket();
Assert.hasText(inputLoginName, "empty email");
Assert.hasText(input.getPassword(), "empty password");
logger.debug("ready to call userMapper.selectByserNameIgnoreCase");
// 查找用户时需要忽略大小写
User tempUser = userMapper.selectByUserNameIgnoreCase(inputLoginName);
......@@ -437,7 +450,7 @@ public class UserServiceImpl extends AbstractService {
logger.debug("创建AtmsTokenDto");
AtmsTokenDto token = new AtmsTokenDto();
newloginResult.getData().setToken(token);
String accessToken = jwtUtil.generateToken(inputLoginName, tempUser.getUserName(), tempUser.getId());
String accessToken = jwtUtil.generateToken(inputLoginName, tempUser.getUserName(), tempUser.getId(),ticket);
token.setAccess_token(accessToken);
token.setToken_type("bearer");
token.setExpires_in(86400000L);
......@@ -474,6 +487,80 @@ public class UserServiceImpl extends AbstractService {
return newloginResult;
}
private OperationResultDto<LoginOutputDto> loginByDDTicket(LoginInputDto input){
OperationResultDto<LoginOutputDto> result = new OperationResultDto<>();
final String ticket = input.getTicket();
Assert.hasText(ticket, "empty ticket");
DDUserInfoRes ddUserInfoRes = new DDUserInfoRes();
try {
String response = HttpUtil.post(getUserInfoUrl+"get_user_by_ticket", "ticket=" + ticket + "&app_id=" + appId, "application/x-www-form-urlencoded", "UTF-8", 10000, 10000);
logger.debug(String.format("DD-get_user_by_ticket返回:[%s]", response));
ddUserInfoRes = JSONObject.parseObject(response,DDUserInfoRes.class);
} catch (Exception e) {
logger.error(String.format("调用DD获取用户信息失败:[%s]", e.getMessage()), e);
}
if(ddUserInfoRes==null){
result.setResult(false);
LoginOutputDto data = new LoginOutputDto();
data.setCheckState(CheckState.UserNameNotExist.value());
result.setData(data);
return result;
}
String userId="";
DDUserInfo userInfo = ddUserInfoRes.getDdUserInfo();
String userName = userInfo.getUsername_zh()==null?input.getEmail():userInfo.getUsername();
User user = userMapper.selectByUserName(userName);
userId = user.getId();
// 根据用户的登录类型选择不同的登录验证方式
result.setResult(true);
LoginOutputDto data = new LoginOutputDto();
data.setCheckState(CheckState.Success.value());
result.setData(data);
final LoginOutputDto resOutputDto = result.getData();
resOutputDto.setUserId(userId);
result.getData().setMessage("Login success.");
AtmsTokenDto token = new AtmsTokenDto();
result.getData().setToken(token);
String accessToken = jwtUtil.generateToken(userName, userName, userId, ticket);
token.setAccess_token(accessToken);
token.setToken_type("bearer");
token.setExpires_in(86400000L);
token.setApi_host("NA");
token.setVat_api_host(apiUrl);
token.setTp_url(apiUrl);
token.setVersion("1.0" + ".0.0");
token.setUser_name(userName);
token.setLocal_name(userName);
token.setNeed_change_password(false);
token.setIs_external_user(true);
token.setUser_id(userId);
token.setTicket(ticket);
WebUserDto userDto = new WebUserDto();
result.getData().setUser(userDto);
userDto.setUniqueId(CommonUtils.getUUID());
userDto.setLoginName(userName);
userDto.setPassword(input.getPassword());
userDto.setHasValidPeriod(false);
// 登陆成功后清除缓存中的用户后台权限
jwtAuthenticationService.removeApiAuthList(userId);
if (logger.isDebugEnabled()) {
logger.debug("print return json:{}", JSON.toJSONString(result, true));
}
return result;
}
private void needChangePassword(User tempUser, OperationResultDto<LoginOutputDto> newloginResult) {
// 这不可能发生,InActive的用户会被activeCheck方法拒绝登录
throw new ApplicationException("Not happens");
......@@ -945,4 +1032,5 @@ public class UserServiceImpl extends AbstractService {
return operationResultDto;
}
}
......@@ -46,3 +46,10 @@ log.debug=${log.debug}
env_type=${env_type}
file_upload_post_url=${file_upload_post_url}
file_upload_query_url=${file_upload_query_url}
#didi-config
check_ticket=${check_ticket}
get_user_info_url=${get_user_info_url}
app_id=${app_id}
app_key=${app_key}
cookie.maxAgeSeconds=${cookie.maxAgeSeconds}
......@@ -42,3 +42,12 @@ log.debug=true
env_type=dev
file_upload_post_url=http://47.94.233.173:11005/resource/erp_tax_system
file_upload_query_url=http://47.94.233.173:11006/resource/erp_tax_system
#didi-config
#ϵַget_user_info_url=http://mis.diditaxi.com.cn/auth/sso/api/
check_ticket=false
get_user_info_url=http://mis-test.diditaxi.com.cn/auth/sso/api/
app_id=2500
app_key=983258e7fd04d7fa0534735f7b1c33f3
cookie.maxAgeSeconds=86400
......@@ -47,3 +47,10 @@ log.debug=false
env_type=pub
file_upload_post_url=http://100.69.238.155:8000/resource/erp_tax_system
file_upload_query_url=http://100.69.238.155:8001/resource/erp_tax_system
#ϵַget_user_info_url=http://mis.diditaxi.com.cn/auth/sso/api/
check_ticket=false
get_user_info_url=http://mis.diditaxi.com.cn/auth/sso/api/
app_id=2500
app_key=983258e7fd04d7fa0534735f7b1c33f3
cookie.maxAgeSeconds=86400
\ No newline at end of file
......@@ -24,7 +24,7 @@ public class JwtUtilTest {
@Test
public void generateTokenThenValidate() {
String token = jwtUtil.generateToken("admin", "Admin", "UUID_OF_ADMIN_USER");
String token = jwtUtil.generateToken("admin", "Admin", "UUID_OF_ADMIN_USER", "TEST_TICKET");
logger.debug("print token:{}", token);
JwtUser jwtUser = jwtUtil.parseToken(token);
logger.debug("print jwtUser:{}", JSON.toJSONString(jwtUser, true));
......
......@@ -34,7 +34,6 @@ import java.util.stream.Collectors;
* @Date: 26/02/2019 11:56
* @Description:
*/
//public class DataInitTest extends CommonIT {
public class DataInitTest extends CommonIT {
private static final Logger logger = LoggerFactory.getLogger(DataInitTest.class);
......
package pwc.taxtech.atms.common;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* 依赖的jar包有:commons-lang-2.6.jar、httpclient-4.3.2.jar、httpcore-4.3.1.jar、commons-io-2.4.jar
* @author zhaoyb
*
*/
public class HttpUtil {
public static final int connTimeout=10000;
public static final int readTimeout=10000;
public static final String charset="UTF-8";
private static HttpClient client = null;
static {
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(128);
cm.setDefaultMaxPerRoute(128);
client = HttpClients.custom().setConnectionManager(cm).build();
}
public static String postParameters(String url, String parameterStr) throws ConnectTimeoutException, SocketTimeoutException, Exception{
return post(url,parameterStr,"application/x-www-form-urlencoded",charset,connTimeout,readTimeout);
}
public static String postParameters(String url, String parameterStr,String charset, Integer connTimeout, Integer readTimeout) throws ConnectTimeoutException, SocketTimeoutException, Exception{
return post(url,parameterStr,"application/x-www-form-urlencoded",charset,connTimeout,readTimeout);
}
public static String postParameters(String url, Map<String, String> params) throws ConnectTimeoutException,
SocketTimeoutException, Exception {
return postForm(url, params, null, connTimeout, readTimeout);
}
public static String postParameters(String url, Map<String, String> params, Integer connTimeout,Integer readTimeout) throws ConnectTimeoutException,
SocketTimeoutException, Exception {
return postForm(url, params, null, connTimeout, readTimeout);
}
public static String get(String url) throws Exception {
return get(url, charset, null, null);
}
public static String get(String url, String charset) throws Exception {
return get(url, charset, connTimeout, readTimeout);
}
/**
* 发送一个 Post 请求, 使用指定的字符集编码.
*
* @param url
* @param body RequestBody
* @param mimeType 例如 application/xml "application/x-www-form-urlencoded" a=1&b=2&c=3
* @param charset 编码
* @param connTimeout 建立链接超时时间,毫秒.
* @param readTimeout 响应超时时间,毫秒.
* @return ResponseBody, 使用指定的字符集编码.
* @throws ConnectTimeoutException 建立链接超时异常
* @throws SocketTimeoutException 响应超时
* @throws Exception
*/
public static String post(String url, String body, String mimeType,String charset, Integer connTimeout, Integer readTimeout)
throws ConnectTimeoutException, SocketTimeoutException, Exception {
HttpClient client = null;
HttpPost post = new HttpPost(url);
String result = "";
try {
if (StringUtils.isNotBlank(body)) {
HttpEntity entity = new StringEntity(body, ContentType.create(mimeType, charset));
post.setEntity(entity);
}
// 设置参数
Builder customReqConf = RequestConfig.custom();
if (connTimeout != null) {
customReqConf.setConnectTimeout(connTimeout);
}
if (readTimeout != null) {
customReqConf.setSocketTimeout(readTimeout);
}
post.setConfig(customReqConf.build());
HttpResponse res;
if (url.startsWith("https")) {
// 执行 Https 请求.
client = createSSLInsecureClient();
res = client.execute(post);
} else {
// 执行 Http 请求.
client = HttpUtil.client;
res = client.execute(post);
}
result = IOUtils.toString(res.getEntity().getContent(), charset);
} finally {
post.releaseConnection();
if (url.startsWith("https") && client != null&& client instanceof CloseableHttpClient) {
((CloseableHttpClient) client).close();
}
}
return result;
}
/**
* 提交form表单
*
* @param url
* @param params
* @param connTimeout
* @param readTimeout
* @return
* @throws ConnectTimeoutException
* @throws SocketTimeoutException
* @throws Exception
*/
public static String postForm(String url, Map<String, String> params, Map<String, String> headers, Integer connTimeout,Integer readTimeout) throws ConnectTimeoutException,
SocketTimeoutException, Exception {
HttpClient client = null;
HttpPost post = new HttpPost(url);
try {
if (params != null && !params.isEmpty()) {
List<NameValuePair> formParams = new ArrayList<NameValuePair>();
Set<Entry<String, String>> entrySet = params.entrySet();
for (Entry<String, String> entry : entrySet) {
formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams, Consts.UTF_8);
post.setEntity(entity);
}
if (headers != null && !headers.isEmpty()) {
for (Entry<String, String> entry : headers.entrySet()) {
post.addHeader(entry.getKey(), entry.getValue());
}
}
// 设置参数
Builder customReqConf = RequestConfig.custom();
if (connTimeout != null) {
customReqConf.setConnectTimeout(connTimeout);
}
if (readTimeout != null) {
customReqConf.setSocketTimeout(readTimeout);
}
post.setConfig(customReqConf.build());
HttpResponse res = null;
if (url.startsWith("https")) {
// 执行 Https 请求.
client = createSSLInsecureClient();
res = client.execute(post);
} else {
// 执行 Http 请求.
client = HttpUtil.client;
res = client.execute(post);
}
return IOUtils.toString(res.getEntity().getContent(), "UTF-8");
} finally {
post.releaseConnection();
if (url.startsWith("https") && client != null
&& client instanceof CloseableHttpClient) {
((CloseableHttpClient) client).close();
}
}
}
/**
* 发送一个 GET 请求
*
* @param url
* @param charset
* @param connTimeout 建立链接超时时间,毫秒.
* @param readTimeout 响应超时时间,毫秒.
* @return
* @throws ConnectTimeoutException 建立链接超时
* @throws SocketTimeoutException 响应超时
* @throws Exception
*/
public static String get(String url, String charset, Integer connTimeout,Integer readTimeout)
throws ConnectTimeoutException,SocketTimeoutException, Exception {
HttpClient client = null;
HttpGet get = new HttpGet(url);
String result = "";
try {
// 设置参数
Builder customReqConf = RequestConfig.custom();
if (connTimeout != null) {
customReqConf.setConnectTimeout(connTimeout);
}
if (readTimeout != null) {
customReqConf.setSocketTimeout(readTimeout);
}
get.setConfig(customReqConf.build());
HttpResponse res = null;
if (url.startsWith("https")) {
// 执行 Https 请求.
client = createSSLInsecureClient();
res = client.execute(get);
} else {
// 执行 Http 请求.
client = HttpUtil.client;
res = client.execute(get);
}
result = IOUtils.toString(res.getEntity().getContent(), charset);
} finally {
get.releaseConnection();
if (url.startsWith("https") && client != null && client instanceof CloseableHttpClient) {
((CloseableHttpClient) client).close();
}
}
return result;
}
/**
* 从 response 里获取 charset
*
* @param ressponse
* @return
*/
@SuppressWarnings("unused")
private static String getCharsetFromResponse(HttpResponse ressponse) {
// Content-Type:text/html; charset=GBK
if (ressponse.getEntity() != null && ressponse.getEntity().getContentType() != null && ressponse.getEntity().getContentType().getValue() != null) {
String contentType = ressponse.getEntity().getContentType().getValue();
if (contentType.contains("charset=")) {
return contentType.substring(contentType.indexOf("charset=") + 8);
}
}
return null;
}
/**
* 创建 SSL连接
* @return
* @throws GeneralSecurityException
*/
private static CloseableHttpClient createSSLInsecureClient() throws GeneralSecurityException {
try {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
public boolean isTrusted(X509Certificate[] chain,String authType) throws CertificateException {
return true;
}
}).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new X509HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
@Override
public void verify(String host, SSLSocket ssl)
throws IOException {
}
@Override
public void verify(String host, X509Certificate cert)
throws SSLException {
}
@Override
public void verify(String host, String[] cns,
String[] subjectAlts) throws SSLException {
}
});
return HttpClients.custom().setSSLSocketFactory(sslsf).build();
} catch (GeneralSecurityException e) {
throw e;
}
}
public static void main(String[] args) {
try {
String str= post("https://localhost:443/ssl/test.shtml","name=12&page=34","application/x-www-form-urlencoded", "UTF-8", 10000, 10000);
//String str= get("https://localhost:443/ssl/test.shtml?name=12&page=34","GBK");
/*Map<String,String> map = new HashMap<String,String>();
map.put("name", "111");
map.put("page", "222");
String str= postForm("https://localhost:443/ssl/test.shtml",map,null, 10000, 10000);*/
System.out.println(str);
} catch (ConnectTimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SocketTimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
\ No newline at end of file
......@@ -13,6 +13,7 @@ public class AtmsTokenDto {
private String user_name;
private String vat_api_host;
private String version;
private String ticket;
public String getAccess_token() {
return access_token;
......@@ -110,6 +111,14 @@ public class AtmsTokenDto {
this.version = version;
}
public String getTicket() {
return ticket;
}
public void setTicket(String ticket) {
this.ticket = ticket;
}
@Override
public String toString() {
return "CookieModel [access_token=" + access_token + ", token_type=" + token_type + ", expires_in=" + expires_in
......
......@@ -6,6 +6,10 @@ public class LoginInputDto {
private String password;
private String ticket;
private Integer type;
public String getEmail() {
return email;
}
......@@ -22,5 +26,19 @@ public class LoginInputDto {
this.password = password;
}
public String getTicket() {
return ticket;
}
public void setTicket(String ticket) {
this.ticket = ticket;
}
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
}
......@@ -2,12 +2,10 @@ package pwc.taxtech.atms.web.controller;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -40,7 +38,7 @@ import pwc.taxtech.atms.dto.OperationResultDto;
import pwc.taxtech.atms.dto.OrganizationStructureDto;
import pwc.taxtech.atms.web.AtmsWebSettings;
/** @see PwC.Tax.Tech.Atms.Web\Controllers\AccountController.cs */
@Controller
@RequestMapping("/Account")
public class AccountController {
......@@ -53,6 +51,11 @@ public class AccountController {
@Autowired
private RestTemplate restTemplate;
// api callback.request
// resultDto (cookie:ticket,code)
// redirct -> #/overview/vat
@RequestMapping(value = "/LogOn", method = RequestMethod.POST)
public @ResponseBody LoginOutputDto login(@RequestBody LoginInputDto input, HttpServletResponse response)
throws UnsupportedEncodingException {
......@@ -75,7 +78,7 @@ public class AccountController {
try {
long start = System.currentTimeMillis();
logger.debug("准备调用atms-api的login接口");
operationResultDto = callApiUserLogin(input.getEmail(), input.getPassword());
operationResultDto = callApiUserLogin(input);
logger.debug("atms-api的login接口返回,用时[{}ms]", System.currentTimeMillis() - start);
} catch (RestClientException e) {
logger.error("调用atms-api的login接口出错:" + e, e);
......@@ -157,17 +160,14 @@ public class AccountController {
return resultLoginOutputDto;
}
private OperationResultDto<LoginOutputDto> callApiUserLogin(String email, String password) {
private OperationResultDto<LoginOutputDto> callApiUserLogin(LoginInputDto input) {
String url = atmsWebSettings.getApiUrl() + "/api/v1/user/login";
logger.debug("Print url:{}", url);
ParameterizedTypeReference<OperationResultDto<LoginOutputDto>> parameterizedTypeReference = new ParameterizedTypeReference<OperationResultDto<LoginOutputDto>>() {
};
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
LoginInputDto loginInputDto = new LoginInputDto();
loginInputDto.setEmail(email);
loginInputDto.setPassword(password);
HttpEntity<LoginInputDto> requestEntity = new HttpEntity<>(loginInputDto, headers);
HttpEntity<LoginInputDto> requestEntity = new HttpEntity<>(input, headers);
ResponseEntity<OperationResultDto<LoginOutputDto>> responseEntity = restTemplate.exchange(url, HttpMethod.POST,
requestEntity, parameterizedTypeReference);
......@@ -180,11 +180,11 @@ public class AccountController {
// operationResultDto.getResult(),
// "operationResultDto.getResult() is false");
return operationResultDto;
}
@RequestMapping(value = { "/LogOut", "/Logout" }, produces = "text/html;charset=UTF-8")
public ModelAndView logout(HttpServletRequest request, HttpServletResponse response) {
@RequestMapping(value = {"/LogOut", "/Logout"}, produces = "text/html;charset=UTF-8")
public void logout(HttpServletRequest request, HttpServletResponse response) {
try {
HttpSession session = request.getSession(false);
if (session != null) {
// 删除会话
......@@ -193,9 +193,25 @@ public class AccountController {
Cookie cookie = new Cookie("AtmsApiToken", "");
cookie.setPath("/");
cookie.setMaxAge(0);
Cookie ddCodeCookie = new Cookie("ddCode", "");
ddCodeCookie.setPath("/");
ddCodeCookie.setMaxAge(0);
Cookie ddTicketCookie = new Cookie("ddTicket", "");
ddTicketCookie.setPath("/");
ddTicketCookie.setMaxAge(0);
Cookie ddJumptoCookie = new Cookie("ddJumpto", "");
ddJumptoCookie.setPath("/");
ddJumptoCookie.setMaxAge(0);
// 删除Cookie
response.addCookie(cookie);
return new ModelAndView("logon");
response.addCookie(ddCodeCookie);
response.addCookie(ddTicketCookie);
response.addCookie(ddJumptoCookie);
// todo 这里写死为DD的登出地址了
response.sendRedirect(" http://mis.diditaxi.com.cn/auth/ldap/logout?app_id=2500");
} catch (Exception e) {
logger.error("登出失败", e);
}
}
......
package pwc.taxtech.atms.web.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.RestTemplate;
import pwc.taxtech.atms.common.HttpUtil;
import pwc.taxtech.atms.dto.AtmsTokenDto;
import pwc.taxtech.atms.dto.LoginOutputDto;
import pwc.taxtech.atms.web.AtmsWebSettings;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
......@@ -16,16 +27,35 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Map;
@Controller
@RequestMapping("/")
public class IndexController {
private static Logger logger = LoggerFactory.getLogger(IndexController.class);
@Value("${api.url}")
private String apiUrl;
@Value("${get_user_info_url}")
private String getUserInfoUrl;
@Value("${app_id}")
private String appId;
@Value("${app_key}")
private String appKey;
@Autowired
JwtUtil jwtUtil;
@Autowired
private AtmsWebSettings atmsWebSettings;
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = {"/", "/index", "/index.html"}, method = RequestMethod.GET)
public String login(@CookieValue(value = "AtmsApiToken", required = false) String atmsApiToken,
@CookieValue(value = "LtpaToken", required = false) String ltpaToken,
......@@ -63,6 +93,28 @@ public class IndexController {
return "redirect:Account/LogOn";
}
@RequestMapping(value = {"/sso/callback"}, method = RequestMethod.GET)
public String ddSSOCallback(@RequestParam(value = "jumpto") String jumpto,
@RequestParam(value = "code") String code,
HttpServletResponse response) throws IOException, ServletException {
try{
String ticketStr = getTicket(code);
Cookie codeCookie = new Cookie("ddCode",URLEncoder.encode(code, "UTF-8"));
codeCookie.setPath("/");
Cookie ddTicket = new Cookie("ddTicket",URLEncoder.encode(ticketStr, "UTF-8"));
ddTicket.setPath("/");
Cookie jumptoCookie = new Cookie("ddJumpto",URLEncoder.encode(jumpto, "UTF-8"));
jumptoCookie.setPath("/");
response.addCookie(codeCookie);
response.addCookie(jumptoCookie);
response.addCookie(ddTicket);
}catch (Exception e){
logger.error("ddSSOCallback error",e);
}
return "redirect:/Account/LogOn";
}
@RequestMapping(value = {"/admin", "/admin.html"}, method = RequestMethod.GET)
public String admin(@CookieValue(value = "AtmsApiToken", required = false) String atmsApiToken) {
if (StringUtils.hasText(atmsApiToken)) {
......@@ -71,4 +123,24 @@ public class IndexController {
return "redirect:Account/LogOn";
}
public String getTicket(String code) {
try{
JSONObject object;
String ddResp = HttpUtil.post(getUserInfoUrl + "check_code", "code=" + code + "&app_key=" + appKey+ "&app_id=" + appId, "application/x-www-form-urlencoded", "UTF-8", 10000, 10000);
object = JSONObject.parseObject(ddResp);
Map<String, Object> res = object.getInnerMap();
int errno = (int) res.get("errno");
if (errno != 0) {
logger.warn(String.format("DD Ticket get Failed:[%s]", object.toJSONString()));
return null;
}else{
Map<String, String> data = (Map)res.get("data");
return data.get("ticket");
}
}catch (Exception e){
logger.error(String.format("通过code:[%s]获取Ticket失败",code));
}
return null;
}
}
api.url=${api.url}
cookie.maxAgeSeconds=${cookie.maxAgeSeconds}
api.url=${api.url}
jwt.base64Secret=${jwt.base64Secret}
jwt.powerToken=${jwt.powerToken}
......@@ -9,3 +7,10 @@ jwt.refreshSecond=${jwt.refreshSecond}
#log
log.level=${log.level}
#didi-config
check_ticket=${check_ticket}
get_user_info_url=${get_user_info_url}
app_id=${app_id}
app_key=${app_key}
cookie.maxAgeSeconds=${cookie.maxAgeSeconds}
api.url=http://dts.erp.didichuxing.com:8180/
cookie.maxAgeSeconds=86400
jwt.base64Secret=TXppQjFlZFBSbnJzMHc0Tg==
jwt.powerToken=xxxx
jwt.expireSecond=180000
jwt.refreshSecond=600
log.level=DEBUG
#didi-config
check_ticket=false
get_user_info_url=http://mis-test.diditaxi.com.cn/auth/sso/api/
app_id=2500
app_key=983258e7fd04d7fa0534735f7b1c33f3
cookie.maxAgeSeconds=86400
\ No newline at end of file
api.url=http://172.20.201.164:8180/
cookie.maxAgeSeconds=86400
jwt.base64Secret=TXppQjFlZFBSbnJzMHc0Tg==
jwt.powerToken=xxxx
jwt.expireSecond=180000
jwt.refreshSecond=600
log.level=INFO
#didi-config
check_ticket=false
get_user_info_url=http://mis-test.diditaxi.com.cn/auth/sso/api/
app_id=2500
app_key=983258e7fd04d7fa0534735f7b1c33f3
cookie.maxAgeSeconds=86400
\ No newline at end of file
......@@ -570,6 +570,6 @@ grunt.registerTask('dev', '开发环境', function () {
'concat:commonJs', 'concat:frameworkJs','concat:frameworkLess',
'concat:taxDocumentManageLess', 'concat:taxDocumentManageJs','concat:appJs',
'concat:vatJs', 'concat:vatCss','concat:vatLess',
'concat:dataImpJs', 'concat:dataImpCss','concat:dataImpLess',
'concat:dataImpJs', 'concat:dataImpCss','concat:dataImpLess','concat:scriptsLogin',
'less', 'copy', 'clean'])
});
......@@ -2,6 +2,10 @@
// store login info.
var loginModel = {};
var checkResult = {};
var cookie = document.cookie;
var ticket = "";
var failFullLoginCount = 0, failMemberLoginCount = 0;
if (!window.console) window.console = {};
......@@ -43,10 +47,12 @@
$('loginFullEmail').focus();
};
var resetLoginModel = function (email, password) {
var resetLoginModel = function (email, password,ticket,type) {
loginModel = {
email: email,
password: password
password: password,
ticket:ticket,
type:type
};
}
......@@ -412,6 +418,27 @@
}
});
};
if(""!==cookie&&getCookie("ddTicket")){
ticket = getCookie("ddTicket");
loginForm.resetLoginModel("DD", "DD".val(),ticket,1);
login($(this), function () {
// todo DD logOut
setTimeout(function () {
resetErrorStatus();
}, 20);
});
}
function getCookie(name) {
var list = cookie.split("; ");
for(var i = 0; i < list.length; i++) {
var arr = list[i].split("=");
if(arr[0] == name)
return decodeURIComponent(arr[1]);
}
return "";
}
// initialize
// bind events
......@@ -424,9 +451,8 @@
// validatorFull.focusInvalid();
return;
}
// set the login data to post
loginForm.resetLoginModel($('#loginFullEmail').val(), $('#loginFullPwd').val());
loginForm.resetLoginModel($('#loginFullEmail').val(), $('#loginFullPwd').val(),ticket,0);
login($(this), function () {
if (!$('#loginFull').valid()) {
//fix bug 1888
......@@ -481,7 +507,7 @@
return;
}
loginForm.resetLoginModel($('#findFullEmail').val(), null);
loginForm.resetLoginModel($('#findFullEmail').val(), null,ticket,0);
// send password over email user entered
sendPassword($('#findFullEmail').val(), $(this), function () {
// case of send email success
......
<!--@using Scripts = System.Web.Optimization.Scripts
@using Styles = System.Web.Optimization.Styles
@{
Layout = null;
}-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" http-equiv="X-UA-Compatible" content="chrome=1; IE=11; IE=10; IE=9; IE=EDGE">
<title>Apex+</title>
<link href="favicon.ico" rel="shortcut icon" type="image/x-icon" />
<!-- @Styles.Render("~/Account/login") -->
<link href="/bundles/accountLogin.css" rel="stylesheet" type="text/css" />
</head>
<body class="login-body">
<!-- @Html.AntiForgeryToken() -->
<div class="login">
<div class="tilte">
<span class="text" id="logo_text">Apex+</span>
</div>
<div id="mainForm" class="form-wrapper">
<form id="loginFull" class="frame form-main-content">
<div class="background-frame">
<img src="/app-resources/images/load-indicator.gif" id="createIndicator" class="loadingImg" style="display:none" alt="loading">
</div>
<!--<div class="loginframe">
<div class="loginfull">
<div class="form-group">
<input id="loginFullEmail" name="loginFullEmail" type="text" placeholder="用户名" class="form-control-customer" />
</div>
<div class="form-group">
<input id="loginFullPwd" name="loginFullPwd" type="password" placeholder="密码" class="form-control-customer" />
</div>
<!--<div class="form-group">-->
<!--<a href="javascript:void(0)" id="btnShowForgotPwd" rel="forgot_password" class="form-forget-password">忘记密码?</a>-->
<!--</div>-->
</div>
<div class="button-wrapper">
<button id="btnFullLogin" class="btn-customer btn-customer-lg login-button" type="button" tabindex="0">登录</button>
</div>
</div> -->
</form>
<form id="forget_password_form" class="frame form-main-content">
<div class="background-frame">
</div>
<div class="loginframe">
<div class="loginfull">
<div class="form-group">
<input id="findFullEmail" name="findFullEmail" type="text" spellcheck="false" placeholder="新密码将会发送至您的注册邮箱" class="form-control-customer" />
</div>
<div class="form-group">
<input type="text" class="form-control-customer" style="visibility:hidden" />
</div>
<div class="form-group">
<a href="javascript:void(0)" rel="forgot_password" class="form-forget-password btnLoginFrame">返回登录?</a>
</div>
</div>
<div class="button-wrapper">
<button id="btnSendPwd" class="btn-customer btn-customer-lg login-button" type="button" tabindex="0">发送</button>
</div>
</div>
</form>
<form id="forget_password_form_sucess" class="frame form-main-content">
<div class="background-frame">
</div>
<div class="loginframe">
<div class="loginfull">
<div class="form-group">
<label class="successMsg"> 邮件发送成功!</label>
</div>
<div class="form-group">
<input type="text" class="form-control-customer" style="visibility:hidden" />
</div>
<div class="form-group">
<a href="javascript:void(0)" rel="forgot_password" class="form-forget-password btnLoginFrame">返回登陆?</a>
</div>
</div>
</div>
</form>
</div>
</div>
<div id="wait" class="notice-center" style="display:none">
<div> 系统正在加载中,请稍等... </div>
<div class='uil-flickr-css' style='transform:scale(0.26);margin:-112px;margin-left: 125px;'> <div></div><div></div></div>
</div>
<!-- @Scripts.Render("~/bundles/modernizr")
@Scripts.Render("~/bundles/jquery", "~/Scripts/login") -->
<script type="text/javascript" src="/bundles/modernizr.js"></script>
<script type="text/javascript" src="/bundles/jquery.js"></script>
<script type="text/javascript" src="/bundles/scriptsLogin.js"></script>
</body>
</html>
/* base color */
a {
color: #404041;
}
a:hover, a:visited, a:active, a:checked {
color: #602320;
}
.badge {
background-color: #968c6d;
}
.navbar-default .navbar-toggle:hover, .navbar-default .navbar-toggle:focus {
/*background-color: #e7e7e8;*/
background-color: #ef9800;
}
.align-right {
float:right;
display:inline-block;
margin-right:15px;
}
.alert-info {
background-image: none;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
background-repeat: repeat-x;
border-color: #c7c8ca;
color: #404041;
background-color: #f5f4f0;
border-color: #c7c8ca;
}
.alert-warning {
background-image: none;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
background-repeat: repeat-x;
border-color: #f7cbc7;
color: #404041;
background-color: #fae2bf;
border-color: #f7cbc7;
}
.alert-danger {
background-image: none;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
background-repeat: repeat-x;
border-color: #e0301e;
color: #FFF;
background-color: #e0301e;
border-color: #e0301e;
}
.cursorpointer {
cursor: pointer;
}
.link-no-underline, .link-no-underline:active, .link-no-underline:hover {
text-decoration: none;
}
.btn-customer {
display: inline-block;
margin-bottom: 0;
font-weight: normal;
text-align: center;
vertical-align: middle;
cursor: pointer;
background-image: none;
border: 1px solid transparent;
white-space: nowrap;
padding: 5px 12px;
line-height: 1.5;
border-radius: 4px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.btn-customer-lg,
.btn-customer-group-lg > .btn-customer {
padding: 6px 12px;
font-size: 20px;
line-height: 1.33;
border-radius: 6px;
}
.btn-customer:focus,
.btn-customer:active:focus,
.btn-customer.active:focus {
outline: thin dotted;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
.btn-customer:hover,
.btn-customer:focus {
/*color: #555555;*/
/*text-decoration: none;*/
}
.btn-customer:active,
.btn-customer.active {
outline: 0;
background-image: none;
background-color: #bed1e1;
}
.btn-customer.disabled,
.btn-customer[disabled],
.form-control-customer {
display: block;
width: 100%;
height: 31px;
padding: 5px 12px;
font-size: 20px;
line-height: 1.5;
color: #555555;
background-color: #ffffff;
background-image: none;
border: 1px solid #cccccc;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
}
.form-control.select-fix {
width: auto;
display: inline-block;
font-size: 14px;
margin-right: 15px;
}
.btn-fix.disabled,
.btn-fix[disabled] {
display: inline-block;
font-size: 14px;
width: auto;
}
.form-control-customer:focus {
border-color: #66afe9;
outline: 0;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
}
.form-control-customer[disabled],
.form-control-customer[readonly],
fieldset[disabled] .form-control-customer {
cursor: not-allowed;
background-color: #f2f2f2;
opacity: 1;
}
textarea.form-control-customer {
height: auto;
}
span.form-control-customer {
border: none;
box-shadow: none;
}
.progress-bar {
background-color: #eb8c00;
}
/* LOGIN */
body.login-body {
background: #999999 url('/app-resources/images/login_pic.jpg') no-repeat;
height: calc(100% - 16px);
background-size: cover;
color: #333;
overflow-y: auto;
}
.login {
display: block;
margin-top: 108px;
margin-left: 120px;
width: 648px;
float: right;
font-family: "Helvetica Neue", Helvetica, Microsoft Yahei, Hiragino Sans GB, WenQuanYi Micro Hei, sans-serif;
}
.tilte {
clear: both;
margin-left: 50px;
width: 227px;
height: 114px;
font-family: 'Papyrus Bold', 'Papyrus';
font-weight: 700;
font-style: normal;
font-size: 72px;
color: #A32020;
}
.tilte .text {
position: absolute;
}
.background-frame {
background-repeat: no-repeat;
/*background-image: url('/app-resources/images/form_bg.png');*/
float: left;
display: block;
width: 643px;
height: 358px;
opacity: 0.7;
z-index: -99;
}
.loginframe {
position: relative;
display: block;
width: 410px;
height: 158px;
float: left;
margin-top: -248px;
z-index: 10;
padding-left: 120px;
}
.frame {
display: none;
}
.show {
display: block !important;
}
/* Form Style */
.form-wrapper {
width: 400px;
font-weight: 400;
font-style: normal;
font-size: 13px;
color: #333333;
text-align: center;
line-height: normal;
margin-top: -45px;
}
.form-wrapper input, .form-wrapper button {
opacity: 1;
}
.loginfull {
width: 270px;
height: 150px;
float: left;
color: white;
clear: both !important;
}
.button-wrapper {
display: block;
float: left;
margin-left: 40px;
height: 150px;
}
.login-button {
background-color: #eb8c00;
color: #fff;
width: 100px;
height: 100px;
}
.login-button:hover {
color: #fff;
background-color: #dc6900;
}
.login-button:disabled {
background-color: #968c6d;
color: #fff;
width: 100px;
height: 100px;
}
.loginfull input::-webkit-input-placeholder {
font-weight: 400;
font-size: 18px;
font-style: normal;
color: #FFFFFF !important;
font-family: "Helvetica Neue", Helvetica, Microsoft Yahei, Hiragino Sans GB, WenQuanYi Micro Hei, sans-serif;
}
.loginfull input:-moz-placeholder {
font-weight: 400;
font-size: 18px;
font-style: normal;
color: #FFFFFF !important;
font-family: "Helvetica Neue", Helvetica, Microsoft Yahei, Hiragino Sans GB, WenQuanYi Micro Hei, sans-serif;
}
.loginfull input::-moz-placeholder {
font-weight: 400;
font-size: 18px;
font-style: normal;
color: #FFFFFF !important;
font-family: "Helvetica Neue", Helvetica, Microsoft Yahei, Hiragino Sans GB, WenQuanYi Micro Hei, sans-serif;
}
.loginfull input:-ms-input-placeholder {
font-weight: 400;
font-size: 18px;
font-style: normal;
color: #FFFFFF !important;
font-family: "Helvetica Neue", Helvetica, Microsoft Yahei, Hiragino Sans GB, WenQuanYi Micro Hei, sans-serif;
}
.loginfull .form-control-customer {
background-color: #404041;
color: #FFFFFF;
font-weight: 400;
font-size: 18px;
font-style: normal;
height: 28px;
border-radius: 10px;
}
.loginfull .form-control-customer.has-error {
border-color: #a94442;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
}
.loginfull .successMsg {
float: left;
text-decoration: none;
color: #a94442;
font-size: 28px;
font-weight: 200;
margin-left: 56px;
}
.loginfull .form-forget-password {
float: left;
text-decoration: none;
color: #dc6900;
font-size: 18px;
font-weight: 200;
margin-left: 6px;
}
.has-error.label {
color: #a94442;
font-weight: 700;
}
.loadingImg {
margin-top: 135px;
z-index: -9;
margin-left: 310px;
}
.form-group {
margin-bottom: 20px;
}
form.active {
display: block !important;
height: auto;
}
form.loginfull .form-group,
form.login .form-group,
form.forgot_password .form-group,
form.email_sent .form-group,
form.forgot_fivetimes .form-group {
margin: 20px 0 20px 0;
}
form.userchoose .form-group {
margin: 0 0 10px 0;
}
.login .list-group-item-heading {
margin: 5px 0 5px 0;
}
/* LOGIN END */
/* Main page */
.navbar-brand {
float: left;
padding: 15.5px 15px;
font-size: 32px;
line-height: 19px;
height: 50px;
font-family: 'Papyrus Bold', 'Papyrus';
font-weight: 700;
font-style: normal;
color: #A32020;
}
.navbar-default .navbar-brand {
color: #A32020;
margin-left: 37px;
margin-right: 37px;
}
.sidebar-closed .navbar-default .navbar-brand {
display: none;
}
.navbar-brand:hover,
.navbar-brand:focus {
color: #A32020;
text-decoration: none;
}
@media (min-width: 768px) {
.navbar > .container .navbar-brand,
.navbar > .container-fluid .navbar-brand {
margin-left: -15px;
}
}
.navbar-fixed-top .navbar-collapse {
max-height: 440px;
}
.panelfix {
margin-bottom: 0;
border-radius: 0;
}
.navbarfix {
border-radius: 0;
}
.nav-split {
background-color: #A32020;
display: inline-block;
height: 42px;
width: 2px;
margin-top: 2px;
float: left;
margin-bottom: 0px;
margin-right: 10px;
}
.nav-company-name {
font-size: 25px;
margin-bottom: 0px;
margin-top: 10px;
font-weight: 100;
}
.nav-company {
display: none;
}
@media(min-width:768px) {
.nav-company {
display: block;
}
}
.navbar-customer {
margin-top: 0px;
width: 46px;
height: 50px;
margin-bottom: 0px;
margin-right: 10px;
padding-left: 11px;
padding-right: 11px;
border-radius: 0;
}
/* Progress */
.row-fix-width {
width: 960px;
}
.progress-table {
text-align: center;
}
.progress-table > tbody > tr > td:first-child {
text-align: left;
}
.progress-table > tbody > tr > td {
border-top: 0px;
}
.progress-table > tbody > tr > td:after {
border-top: 0px;
}
.progress-title {
text-shadow: none;
}
.btn-city {
width: 130px;
text-align: left;
}
.btn-default.step1 {
background-color: #e5e2db;
}
.btn-default.step2 {
background-color: #fae2bf;
}
.btn-default.step3 {
background-color: #f7cbc7;
}
.btn-default.step4 {
background-color: #f6d4da;
}
.btn-default.step5 {
background-color: #d7c8c7;
}
.btn-default.step6 {
background-color: #e5e2db;
}
.btn-default.review {
color: white;
background-color: #a32020;
}
.btn-default.signoff {
color: white;
background-color: #dc6900;
}
.td-line:after {
content: "";
position: absolute;
margin-top: -16px;
width: 150px;
border-bottom: 2px dashed #ccc;
}
.tr-hr:after {
content: "";
position: absolute;
margin-top: 23px;
margin-left: -720px;
width: 680px;
border-bottom: 2px dashed #e8c7c7;
}
.btn-customer.disabled, .btn-customer[disabled], fieldset[disabled] .btn-customer {
opacity: 0.5;
}
.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
border-top-right-radius: 15px;
border-bottom-right-radius: 15px;
}
.bootstrap-switch-gap {
margin-right: 10px;
}
.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-primary, .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-primary {
background: #a32020;
}
.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-primary:hover, .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-primary:hover {
background: #602320;
}
.bootstrap-switch.bootstrap-switch-focused {
border-color: #dc6900;
}
/* tab begin */
.nav-tabs > li .close {
margin: -2px 0 0 10px;
font-size: 18px;
}
.marginBottom {
padding-top: 3px;
margin-bottom: 1px !important;
margin-left: -15px;
}
.operationDiv {
padding: 5px 10px 5px 5px;
}
.operationDivWrapper {
margin-top: -1px;
}
.firstTab {
margin-left: 15px;
}
.leftMenu {
height: 70%;
background-color: #E6E6E6;
border-right: 2px solid #BFBFBF;
}
.close-tab-button {
margin-top: -41px;
margin-right: 6px;
font-size: 18px;
margin: -41px 6px 0 0 !important;
}
/* tab end */
.btn-position-fix {
margin-top: 25px;
}
.removeBackgroud > li > a:focus {
background-color: transparent;
color: #000;
}
.notice-center {
position: fixed;
top: 50%;
left: 50%;
/*background-color: #000;
width:50%;
height: 50%;*/
-webkit-transform: translateX(-50%) translateY(-50%);
-webkit-transform: translateX(-50%) translateY(-50%);
-moz-transform: translateX(-50%) translateY(-50%);
-ms-transform: translateX(-50%) translateY(-50%);
transform: translateX(-50%) translateY(-50%);
}
@-webkit-keyframes uil-flickr-anim1 {
0% {
left: 0;
}
50% {
left: 100px;
}
100% {
left: 0;
}
}
@-webkit-keyframes uil-flickr-anim1 {
0% {
left: 0;
}
50% {
left: 100px;
}
100% {
left: 0;
}
}
@-moz-keyframes uil-flickr-anim1 {
0% {
left: 0;
}
50% {
left: 100px;
}
100% {
left: 0;
}
}
@-ms-keyframes uil-flickr-anim1 {
0% {
left: 0;
}
50% {
left: 100px;
}
100% {
left: 0;
}
}
@-moz-keyframes uil-flickr-anim1 {
0% {
left: 0;
}
50% {
left: 100px;
}
100% {
left: 0;
}
}
@-webkit-keyframes uil-flickr-anim1 {
0% {
left: 0;
}
50% {
left: 100px;
}
100% {
left: 0;
}
}
@-o-keyframes uil-flickr-anim1 {
0% {
left: 0;
}
50% {
left: 100px;
}
100% {
left: 0;
}
}
@keyframes uil-flickr-anim1 {
0% {
left: 0;
}
50% {
left: 100px;
}
100% {
left: 0;
}
}
width: 100%; @-webkit-keyframes uil-flickr-anim2 {
0%;
{
left: 100px;
z-index: 1;
}
49% {
z-index: 1;
}
50% {
left: 0;
z-index: 10;
}
100% {
left: 100px;
z-index: 10;
}
}
@-webkit-keyframes uil-flickr-anim2 {
0% {
left: 100px;
z-index: 1;
}
49% {
z-index: 1;
}
50% {
left: 0;
z-index: 10;
}
100% {
left: 100px;
z-index: 10;
}
}
@-moz-keyframes uil-flickr-anim2 {
0% {
left: 100px;
z-index: 1;
}
49% {
z-index: 1;
}
50% {
left: 0;
z-index: 10;
}
100% {
left: 100px;
z-index: 10;
}
}
@-ms-keyframes uil-flickr-anim2 {
0% {
left: 100px;
z-index: 1;
}
49% {
z-index: 1;
}
50% {
left: 0;
z-index: 10;
}
100% {
left: 100px;
z-index: 10;
}
}
@-moz-keyframes uil-flickr-anim2 {
0% {
left: 100px;
z-index: 1;
}
49% {
z-index: 1;
}
50% {
left: 0;
z-index: 10;
}
100% {
left: 100px;
z-index: 10;
}
}
@-webkit-keyframes uil-flickr-anim2 {
0% {
left: 100px;
z-index: 1;
}
49% {
z-index: 1;
}
50% {
left: 0;
z-index: 10;
}
100% {
left: 100px;
z-index: 10;
}
}
@-o-keyframes uil-flickr-anim2 {
0% {
left: 100px;
z-index: 1;
}
49% {
z-index: 1;
}
50% {
left: 0;
z-index: 10;
}
100% {
left: 100px;
z-index: 10;
}
}
@keyframes uil-flickr-anim2 {
0% {
left: 100px;
z-index: 1;
}
49% {
z-index: 1;
}
50% {
left: 0;
z-index: 10;
}
100% {
left: 100px;
z-index: 10;
}
}
.uil-flickr-css {
background: none;
position: relative;
width: 200px;
height: 200px;
}
.uil-flickr-css > div {
width: 100px;
height: 100px;
border-radius: 50px;
position: absolute;
top: 50px;
}
.uil-flickr-css > div:nth-of-type(1) {
left: 0;
background: #e35839;
z-index: 5;
-ms-animation: uil-flickr-anim1 1s linear infinite;
-moz-animation: uil-flickr-anim1 1s linear infinite;
-webkit-animation: uil-flickr-anim1 1s linear infinite;
-o-animation: uil-flickr-anim1 1s linear infinite;
animation: uil-flickr-anim1 1s linear infinite;
}
.uil-flickr-css > div:nth-of-type(2) {
left: 100px;
background: #d28d4f;
-ms-animation: uil-flickr-anim2 1s linear infinite;
-moz-animation: uil-flickr-anim2 1s linear infinite;
-webkit-animation: uil-flickr-anim2 1s linear infinite;
-o-animation: uil-flickr-anim2 1s linear infinite;
animation: uil-flickr-anim2 1s linear infinite;
}
/* datepicker */
.datepicker table tr td span.active.active, .datepicker table tr td span.active.disabled.active, .datepicker table tr td span.active.disabled:active, .datepicker table tr td span.active.disabled:hover.active, .datepicker table tr td span.active.disabled:hover:active, .datepicker table tr td span.active:active, .datepicker table tr td span.active:hover.active, .datepicker table tr td span.active:hover:active {
color: #fff;
background-color: #eb8c00;
}
.datepicker table tr td span.active, .datepicker table tr td span.active.disabled, .datepicker table tr td span.active.disabled:hover, .datepicker table tr td span.active:hover {
color: #fff;
background-color: #eb8c00;
}
.datepicker table tr td span.active.active.focus, .datepicker table tr td span.active.active:focus, .datepicker table tr td span.active.active:hover, .datepicker table tr td span.active.disabled.active.focus, .datepicker table tr td span.active.disabled.active:focus, .datepicker table tr td span.active.disabled.active:hover, .datepicker table tr td span.active.disabled:active.focus, .datepicker table tr td span.active.disabled:active:focus, .datepicker table tr td span.active.disabled:active:hover, .datepicker table tr td span.active.disabled:hover.active.focus, .datepicker table tr td span.active.disabled:hover.active:focus, .datepicker table tr td span.active.disabled:hover.active:hover, .datepicker table tr td span.active.disabled:hover:active.focus, .datepicker table tr td span.active.disabled:hover:active:focus, .datepicker table tr td span.active.disabled:hover:active:hover, .datepicker table tr td span.active:active.focus, .datepicker table tr td span.active:active:focus, .datepicker table tr td span.active:active:hover, .datepicker table tr td span.active:hover.active.focus, .datepicker table tr td span.active:hover.active:focus, .datepicker table tr td span.active:hover.active:hover, .datepicker table tr td span.active:hover:active.focus, .datepicker table tr td span.active:hover:active:focus, .datepicker table tr td span.active:hover:active:hover {
color: #fff;
background-color: #dc6900;
}
.datepicker table tr td, .datepicker table tr th {
text-align: center;
}
/* ui select */
.ui-select-no-border, .ui-select-has-border {
display: inline-block;
cursor: pointer;
}
.search-container.ui-select-search-hidden {
display: none;
}
.ui-select-no-border .select2-container-active .select2-choice,
.ui-select-no-border .select2-container-active .select2-choices {
border: 1px solid rgba(0, 0, 0, 0.15);
}
.ui-select-no-border .select2-results .select2-highlighted {
background: #e0301e;
}
.ui-select-no-border .select2-results li,
.ui-select-no-border .select2-results,
.ui-select-no-border .select2-container {
outline: none;
}
.ui-select-no-border .select2-drop,
.ui-select-no-border .select2-dropdown-open .select2-choice,
.ui-select-no-border .select2-container-active .select2-choice,
.ui-select-no-border .select2-container-active .select2-choices {
border-radius: 0;
box-shadow: none;
-webkit-box-shadow: none;
}
.ui-select-no-border .select2-drop-active {
border: 1px solid rgba(0, 0, 0, 0.15);
}
.ui-select-no-border .select2-container .select2-choice .select2-arrow {
margin-right: 8px;
}
.ui-select-no-border .select2-container .select2-choice .select2-arrow,
.ui-select-no-border .select2-dropdown-open .select2-choice {
border-left: none;
background: none;
background-image: none;
}
.ui-select-no-border .select2-container .select2-choice .select2-arrow b {
background: url(/app-resources/images/vat/down.png) no-repeat scroll right center transparent;
}
.ui-select-no-border .select2-container .select2-choice {
border: none;
background-image: none;
background: none;
}
.ui-select-has-border .select2-drop-active {
border: 1px solid #adb4bd;
border-top: 1px solid #adb4bd;
}
.ui-select-has-border .select2-dropdown-open .select2-choice {
box-shadow: none;
background-color: none;
}
.ui-select-has-border .select2-container-active .select2-choices {
border: none;
}
.ui-select-has-border .select2-results .select2-highlighted {
background: #e0301e;
}
.ui-select-has-border .select2-container-active .select2-choice,
.ui-select-has-border .select2-container-active .select2-choices {
border: 1px solid #aaa;
}
.ui-select-has-border .select2-results li,
.ui-select-has-border .select2-results,
.ui-select-has-border .select2-container {
outline: none;
}
.ui-select-has-border .select2-container .select2-choice .select2-arrow {
border-left: none;
background: none;
background-image: none;
}
.ui-select-has-border .select2-container .select2-choice .select2-arrow b {
margin-top: 2px;
}
.ui-select-has-border .select2-container .select2-choice,
.ui-select-has-border .select2-container-active .select2-choice {
background-image: none;
background: none;
outline: none;
height: 34px;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857143;
color: #555555;
background-color: #ffffff;
background-image: none;
border: 1px solid #cccccc;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
-o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
}
.dx-checkbox-checked .dx-checkbox-icon {
color: #e0301e;
}
.dx-checkbox-indeterminate .dx-checkbox-icon:before {
background-color: #e0301e;
}
.dx-texteditor.dx-state-hover {
border-color: rgba(239, 213, 189, 0.5);
}
.dx-texteditor.dx-state-focused,
.dx-texteditor.dx-state-active {
border-color: rgba(239, 213, 189, 0.5);
}
.dx-list.dx-list-select-decorator-enabled .dx-list-item.dx-state-focused .dx-radiobutton-icon:before,
.dx-list.dx-list-select-decorator-enabled .dx-list-item.dx-state-focused .dx-checkbox-icon {
border: 1px solid rgba(239, 213, 189, 0.5);
}
.dx-list:not(.dx-list-select-decorator-enabled) .dx-list-item.dx-state-focused {
background-color: #dc6900;
}
.dx-list:not(.dx-list-select-decorator-enabled) .dx-list-item.dx-state-focused.dx-list-item-selected {
background-color: #dc6900;
}
.dx-list:not(.dx-list-select-decorator-enabled) .dx-list-item.dx-state-active {
background-color: #dc6900;
}
.dx-list:not(.dx-list-select-decorator-enabled) .dx-list-item.dx-state-active .dx-list-slide-item-content {
background-color: #dc6900;
}
.dx-list-item.dx-list-item-ghost-reordering.dx-state-focused.dx-state-hover {
border-top: 1px solid rgba(239, 213, 189, 0.5);
border-bottom: 1px solid rgba(239, 213, 189, 0.5);
}
.dx-list-slide-menu-button-menu {
background-color: #dc6900;
}
.dx-checkbox.dx-state-hover .dx-checkbox-icon {
border: 1px solid rgba(239, 213, 189, 0.5);
}
.dx-checkbox.dx-state-focused .dx-checkbox-icon {
border: 1px solid rgba(239, 213, 189, 0.5);
}
.dx-treeview .dx-treeview-node.dx-treeview-item-with-checkbox.dx-state-focused > .dx-checkbox .dx-checkbox-icon {
border: 1px solid rgba(239, 213, 189, 1);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment