精华内容
下载资源
问答
  • 天翼视讯手机号码免密登录
  • 最近手机号验证又发生了一项黑科技,简验推出一键免密登录,大部分手机应用不用输入手机号,不需获取验证密码,点击登录,一键获取本地手机号就可登录。 简验一键免密登录 这种极佳的用户体验,对于用户和企业以及...

    最近手机号验证又发生了一项黑科技,简验推出一键免密登录,大部分手机应用不用输入手机号,不需获取验证密码,点击登录,一键获取本地手机号就可登录。

    简验一键免密登录在这里插简验入图片描述
    这种极佳的用户体验,对于用户和企业以及运营者都是很好的选择

    对于用户而言
    1.不需要输入手机号
    2.不需要获取验证码
    3.不需要输入验证码
    4.不需要记忆各种应用平台的密码
    5.直接手机号一键登录

    对于企业而言
    1.减少开发成本
    2.减少运营成本
    3.防止短信黑名单
    4.防止短信拦截
    5.与运营商直接对接,全程加密,防止劫持
    6.提升体验
    7.提升用户转化率

    运营者也不用绞尽脑汁的引导用户绑定手机号,降低登录注册环节的用户流程,企业只需接入SDK即可实现一键免密登录功能。
    这种基于运营商特有的“网关+短验能力”,一键获取用户本地手机号,无需短信验证码下发,即可使接入简验产品能力的移动端应用快速完成用户本机号码身份核验,从而极大提升用户体验度和转化率。

    简验产品能力可以广泛接入到移动应用的注册、登录、密码找回、安全手机校验、身份认证等各种业务场景,为企业提供体验优化、转化提升、成本节约的综合解决方案。

    目前这一项服务会逐渐被各个平台所使用,当你的竞争对手已经接入使用的时候,他们已经快你一步占领市场,APP的运营者、产品经理你们还在等什么。手机号已经成为互联网时代的线上“身份证”。

    展开全文
  • 主要在登录界面增加了手机号登录: <template> <div class="login-container"> <el-tabs v-model="activeName" type="card"> <el-tab-pane label="账号/密码登陆" name="name"> .....

    效果展示

    在这里插入图片描述

    前端设计

    主要在登录界面增加了手机号登录:

    	<template>
    	  <div class="login-container">
    	    <el-tabs v-model="activeName" type="card">
    	      <el-tab-pane label="账号/密码登陆" name="name">
    	        <el-form
    	          :rules="nameRules"
    	          label-position="left"
    	          label-width="0px"
    	          v-loading="loading"
    	          :model="nameLoginForm"
    	          ref="nameForm"
    	          status-icon
    	        >
    	          <h3 class="login_title">系统登录</h3>
    	          <el-form-item prop="account">
    	            <el-input
    	              type="text"
    	              v-model="nameLoginForm.username"
    	              auto-complete="off"
    	              placeholder="账号"
    	            ></el-input>
    	          </el-form-item>
    	          <el-form-item prop="checkPass">
    	            <el-input
    	              type="password"
    	              v-model="nameLoginForm.password"
    	              auto-complete="off"
    	              placeholder="密码"
    	            ></el-input>
    	          </el-form-item>
    	          <div></div>
    	          <el-form-item style="width: 100%">
    	            <el-button type="primary" @click.native.prevent="submitNameClick" style="width: 100%">登录</el-button>
    	          </el-form-item>
    	        </el-form>
    	      </el-tab-pane>
    	
    	      <el-tab-pane label="手机免密登陆" name="phone">
    	        <el-form
    	          :rules="phoneRules"
    	          label-position="left"
    	          label-width="0px"
    	          v-loading="loading"
    	          :model="phoneLoginForm"
    	          ref="phoneForm"
    	          status-icon
    	        >
    	          <h3 class="login_title">系统登录</h3>
    	          <el-form-item prop="phone">
    	            <el-input
    	              type="text"
    	              v-model="phoneLoginForm.phone"
    	              auto-complete="off"
    	              placeholder="手机号"
    	            ></el-input>
    	          </el-form-item>
    	          <el-form-item prop="checkCode">
    	            <el-input v-model="phoneLoginForm.checkCode" auto-complete="off" placeholder="5位验证码">
    	              <template slot="append">
    	                <span v-if="!send" @click="sendCheckCode">{{msg}}</span>
    	                <span v-else>{{msg}}</span>
    	              </template>
    	            </el-input>
    	          </el-form-item>
    	          <el-form-item style="width: 100%">
    	            <el-button
    	              type="primary"
    	              @click.native.prevent="submitPhoneClick"
    	              style="width: 100%"
    	            >登录</el-button>
    	          </el-form-item>
    	        </el-form>
    	      </el-tab-pane>
    	    </el-tabs>
    	  </div>
    	</template>
    	<script>
    	import { get, post } from "@/utils/http";
    	export default {
    	  data() {
    	    var phoneCheck = (rule, value, callback) => {
    	      var value = this.phoneLoginForm.phone;
    	      if (!value) {
    	        return callback(new Error("年龄不能为空"));
    	      }
    	      var reg = /^[1][3,4,5,7,8][0-9]{9}$/;
    	      if (!reg.test(value)) {
    	        return callback(new Error("请输入正确的手机号"));
    	      }
    	      callback();
    	    };
    	    var nameCheck = (rule, value, callback) => {
    	      var value = this.nameLoginForm.username;
    	      if (!value) {
    	        return callback(new Error("用户名不能为空"));
    	      }
    	      callback();
    	    };
    	    var passwordCheck = (rule, value, callback) => {
    	      var value = this.nameLoginForm.password;
    	      if (!value) {
    	        return callback(new Error("密码不能为空"));
    	      }
    	      if (value.length < 6) {
    	        return callback(new Error("密码需大于6位"));
    	      }
    	      callback();
    	    };
    	    var checkCodeCheck = (rule, value, callback) => {
    	      var value = this.phoneLoginForm.checkCode;
    	      if (!value) {
    	        return callback(new Error("验证码不能为空"));
    	      }
    	      if (value.length != 5) {
    	        return callback(new Error("验证码为5位"));
    	      }
    	      callback();
    	    };
    	    return {
    	      activeName: "name",
    	      send: false,
    	      msg: "获取验证码",
    	      nameRules: {
    	        account: [{ validator: nameCheck, trigger: "blur" }],
    	        checkPass: [{ validator: passwordCheck, trigger: "blur" }]
    	      },
    	      phoneRules: {
    	        phone: [{ validator: phoneCheck, trigger: "blur" }],
    	        checkCode: [{ validator: checkCodeCheck, trigger: "blur" }]
    	      },
    	      nameLoginForm: {
    	        username: "",
    	        password: ""
    	      },
    	      phoneLoginForm: {
    	        phone: "",
    	        checkCode: ""
    	      },
    	      loading: false
    	    };
    	  },
    	  methods: {
    	    submitNameClick() {
    	      var _this = this;
    	      this.loading = true;
    	      this.$refs["nameForm"].validate(valid => {
    	        if (valid) {
    	          post("/user/uLogin", {
    	            username: this.nameLoginForm.username,
    	            password: this.nameLoginForm.password
    	          }).then(
    	            resp => {
    	              _this.loading = false;
    	              var result = resp.result;
    	              if (resp.code === 200) {
    	                _this.$store.commit("setUsername", this.nameLoginForm.username);
    	                _this.$store.commit("setUserInfo", result);
    	                this.$router.replace({ path: "/" });
    	                _this.$message.success(resp.msg);
    	              } else {
    	                this.$message.error(resp.msg);
    	              }
    	            },
    	            resp => {
    	              _this.loading = false;
    	              _this.$alert("找不到服务器");
    	            }
    	          );
    	        } else {
    	          _this.$message.error("信息填写错误");
    	          _this.loading = false;
    	        }
    	      });
    	    },
    	    submitPhoneClick() {
    	      var _this = this;
    	      this.loading = true;
    	      this.$refs.phoneForm.validate(valid => {
    	        if (valid) {
    	          post("/user/pLogin", {
    	            phone: this.phoneLoginForm.phone,
    	            checkCode: this.phoneLoginForm.checkCode
    	          }).then(
    	            resp => {
    	              _this.loading = false;
    	              var result = resp.result;
    	              if (resp.code === 200) {
    	                _this.$store.commit("setUserInfo", result);
    	                this.$router.replace({ path: "/" });
    	                _this.$message.success(resp.msg);
    	              } else {
    	                this.$message.error(resp.msg);
    	              }
    	            },
    	            resp => {
    	              _this.loading = false;
    	              _this.$alert("找不到服务器⊙﹏⊙∥!", "失败!");
    	            }
    	          );
    	        } else {
    	          _this.$message.error("信息填写错误");
    	          _this.loading = false;
    	        }
    	      });
    	    },
    	    sendCheckCode() {
    	      var reg = /^[1][3,4,5,7,8][0-9]{9}$/;
    	      if (!reg.test(this.phoneLoginForm.phone)) {
    	        this.$message.error("请输入正确的手机号");
    	        return;
    	      }
    	      this.send = true;
    	      let time = 60;
    	      post("/user/code", {phone: this.phoneLoginForm.phone }).then(res => {
    	        this.$message({
    	          message: "验证码为12345",
    	          type: "success"
    	        });
    	      });
    	      let timer = setInterval(() => {
    	        if (time == 0) {
    	          clearInterval(timer);
    	          this.send = false;
    	          this.msg = "获取验证码";
    	        } else {
    	          this.msg = time + "秒后重试";
    	
    	          time--;
    	        }
    	      }, 1000);
    	      
    	    }
    	  }
    	};
    	</script>
    	<style>
    	.login-container {
    	  border-radius: 15px;
    	  background-clip: padding-box;
    	  margin: 10% auto;
    	  width: 350px;
    	  padding: 35px 35px 15px 35px;
    	  background: #fff;
    	  border: 1px solid #eaeaea;
    	  box-shadow: 0 0 25px #cac6c6;
    	}
    	
    	.login_title {
    	  margin: 0px auto 40px auto;
    	  text-align: center;
    	  color: #505458;
    	}
    	</style>
    

    后端

    针对普通的账号密码登陆,我们的控制层写法保存不变:

    	@PostMapping("/uLogin")
    	    public Response login(@RequestBody JSONObject object, HttpServletRequest request){
    	        Subject subject = SecurityUtils.getSubject();
    	        UsernamePasswordToken token = new UsernamePasswordToken(object.getString("username"),object.getString("password"));
    	        try {
    	            subject.login(token);
    	            userService.addLoginLog(object.getString("username"),IpUtil.getIpAddr(request));
    	            User user = userService.getUserByName(object.getString("username"));
    	            Map<String,Object> result = new HashMap<>();
    	            result.put("uid",user.getId());
    	            result.put("username",user.getUsername());
    	            result.put("rid",user.getRid());
    	            result.put("token",subject.getSession().getId());
    	            return Response.Success("登录成功",result);
    	        } catch (UnknownAccountException e) {
    	            return Response.Fail("该账户不存在");
    	        }catch (LockedAccountException e){
    	            return Response.Fail("该账户已被锁定,请联系管理员");
    	        }catch (AuthenticationException e) {
    	            return Response.Fail("账号或密码错误");
    	        }
    	    }
    

    对于手机号登录的用户:

    • 控制层

      @PostMapping("/pLogin")
          public Response Login(@RequestBody JSONObject object) {
              Subject subject = SecurityUtils.getSubject();
              PhoneToken token = new PhoneToken(object.getString("phone"));
              try{
              //登录先验证输入的验证码是否与redis中存储的匹配
                  if(userService.verifyCheckCode(object.getString("phone"),object.getString("checkCode")))
                      subject.login(token);
                  else{
                      return Response.Fail("验证码错误");
                  }
                  User user = userService.getUserByPhone(object.getString("phone"));
                  Map<String,Object> result = new HashMap<>();
                  result.put("uid",user.getId());
                  result.put("username",user.getUsername());
                  result.put("rid",user.getRid());
                  result.put("token",subject.getSession().getId());
                  return Response.Success("登录成功",result);
              }catch (LockedAccountException e){
                  return Response.Fail("该账户已被锁定,请联系管理员");
              }
          }
      
    • 写一个新的Token,类似shiro已有的usernamepasswordToken

      public class PhoneToken  implements HostAuthenticationToken, Serializable {
      
          private String phone;
          private String host;
      
          public PhoneToken() {
          }
      
          public PhoneToken(String phone) {
              this.phone = phone;
          }
      
          @Override
          public Object getPrincipal() {
              return phone;
          }
      
          @Override
          public Object getCredentials() {
              return phone;
          }
      
          public String getPhone() {
              return phone;
          }
      
          public void setPhone(String phone) {
              this.phone = phone;
          }
      
          @Override
          public String getHost() {
              return host;
          }
      }
      
    • 写一个新的Realm,设定手机号验证的方式

      public class PhoneRealm extends AuthorizingRealm {
      
          @Autowired
          private UserService userService;
      
          @Autowired
          private UserAuthService userAuthService;
      
          @Override
          public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
              //这儿的CredentialsMatcher的new的对象必须是AllowAllCredentialsMatcher
              CredentialsMatcher matcher = new AllowAllCredentialsMatcher();
              super.setCredentialsMatcher(matcher);
          }
      
          @Override
          protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
              String phone = principals.getPrimaryPrincipal().toString();
              Set<String> permissions = userAuthService.getUserPermission(userService.getUserByName(phone).getId());
      
              // 将权限放入授权信息中
              SimpleAuthorizationInfo s = new SimpleAuthorizationInfo();
              s.setStringPermissions(permissions);
              return s;
          }
      
          @Override
          protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
              PhoneToken token = (PhoneToken) authenticationToken;
              String phone = token.getPrincipal().toString();
              User user = userService.getUserByPhone(phone);
              if(user == null){//如果手机号不存在
                  user = userService.addUserByPhone(phone);//自动添加该用户
                  userAuthService.addUserRole(user.getId(),3);//添加默认角色
              }else {
                  if (!user.getStatus()) {
                      throw new LockedAccountException();
                  }
              }
              return new SimpleAuthenticationInfo(user,phone,getName());
      
          }
      
          /**
           * 用来判断是否使用当前的 realm
           * @param var1 传入的token
           * @return true就使用,false就不使用
           */
          @Override
          public boolean supports(AuthenticationToken var1) {
              return var1 instanceof PhoneToken;
          }
      }
      
    • 配置ShiroConfig(完整的ShiroConfig)

      @Configuration
      public class ShiroConfig {
      
          @Bean
          public static LifecycleBeanPostProcessor getLifecycleBeanProcessor() {
              return new LifecycleBeanPostProcessor();
          }
      
          @Bean
          public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
              ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
              shiroFilterFactoryBean.setSecurityManager(securityManager);
              Map<String, String > filterChainDefinitionMap = new LinkedHashMap<>();
              Map<String, Filter> customizedFilter = new HashMap<>();
      
              // 设置自定义过滤器名称为 url
              customizedFilter.put("url", getURLPathMatchingFilter());
      
              // 对管理接口的访问启用自定义拦截(url 规则),即执行 URLPathMatchingFilter 中定义的过滤方法
              filterChainDefinitionMap.put("/**", "url");
              // 启用自定义过滤器
              shiroFilterFactoryBean.setFilters(customizedFilter);
              filterChainDefinitionMap.put("/user/login","anon");
              filterChainDefinitionMap.put("/user/register","authc");
              filterChainDefinitionMap.put("/user/logout","authc");
              filterChainDefinitionMap.put("/user/getAuth", "authc");
              shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
              return shiroFilterFactoryBean;
          }
      
          @Bean
          public SecurityManager securityManager(AbstractAuthenticator abstractAuthenticator) {
              DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
              List<Realm> realms = new ArrayList<>();
              realms.add(getUserRealm());
              realms.add(getPhoneRealm());
              securityManager.setRealms(realms);
              securityManager.setAuthenticator(abstractAuthenticator);
              securityManager.setRememberMeManager(rememberMeManager());
              return securityManager;
          }
      
          @Bean
          public UserRealm getUserRealm() {
              UserRealm realm = new UserRealm();
              realm.setCredentialsMatcher(hashedCredentialsMatcher());
              return realm;
          }
      
          @Bean
          public PhoneRealm getPhoneRealm(){
              return new PhoneRealm();
          }
          @Bean
          public UrlPathMatchFilter getURLPathMatchingFilter() {
              return new UrlPathMatchFilter();
          }
      
          @Bean
          public CredentialsMatcher hashedCredentialsMatcher() {
              HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
              hashedCredentialsMatcher.setHashAlgorithmName("md5");
              hashedCredentialsMatcher.setHashIterations(2);
              return hashedCredentialsMatcher;
          }
      
          @Bean
          public AbstractAuthenticator abstractAuthenticator(UserRealm userRealm, PhoneRealm phoneRealm){
              // 自定义模块化认证器,用于解决多realm抛出异常问题
              //shiro只会抛出一个AuthenticationException异常
              ModularRealmAuthenticator authenticator = new MyCustomModularRealmAuthenticator();
              // 认证策略:AtLeastOneSuccessfulStrategy(默认),AllSuccessfulStrategy,FirstSuccessfulStrategy
              authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
              // 加入realms
              List<Realm> realms = new ArrayList<>();
              realms.add(userRealm);
              realms.add(phoneRealm);
              authenticator.setRealms(realms);
              return authenticator;
          }
      
          @Bean
          public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
              AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
              authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
              return authorizationAttributeSourceAdvisor;
          }
      
          public CookieRememberMeManager rememberMeManager() {
              CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
              cookieRememberMeManager.setCookie(rememberMeCookie());
              cookieRememberMeManager.setCipherKey("REMEMBER_MANAGER".getBytes());
              return cookieRememberMeManager;
          }
      
          @Bean
          public SimpleCookie rememberMeCookie() {
              SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
              simpleCookie.setMaxAge(7*24*60*60);//秒为单位
              return simpleCookie;
          }
      }
      
    • MyCustomModularRealmAuthenticator.java

      public class MyCustomModularRealmAuthenticator extends ModularRealmAuthenticator {
          @Override
          protected AuthenticationInfo doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token) {
              AuthenticationStrategy authenticationStrategy = this.getAuthenticationStrategy();
              AuthenticationInfo authenticationInfo = authenticationStrategy.beforeAllAttempts(realms,token);
      
              Iterator var5 = realms.iterator();
              while(var5.hasNext()) {
                  Realm realm = (Realm)var5.next();
                  authenticationInfo = authenticationStrategy.beforeAttempt(realm, token, authenticationInfo);
                  if (realm.supports(token)) {
      
                      AuthenticationInfo info = null;
                      Throwable t = null;
      
                      info = realm.getAuthenticationInfo(token);
      
                      authenticationInfo = authenticationStrategy.afterAttempt(realm, token, info, authenticationInfo, t);
                  }
              }
              authenticationInfo = authenticationStrategy.afterAllAttempts(token, authenticationInfo);
              return authenticationInfo;
          }
      }
      

    额外

    1. shiro的过滤器拦截
      public class UrlPathMatchFilter extends PathMatchingFilter {
      
          @Autowired
          private UserAuthService userAuthService;
      
          @Autowired
          private UserService userService;
      
          @Override
          protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
              HttpServletRequest httpServletRequest = (HttpServletRequest) request;
              HttpServletResponse httpServletResponse = (HttpServletResponse) response;
              // 放行 options 请求
              if (HttpMethod.OPTIONS.toString().equals((httpServletRequest).getMethod())) {
                  httpServletResponse.setStatus(HttpStatus.NO_CONTENT.value());
                  return true;
              }
              if (null==userAuthService) {
                  userAuthService = SpringContextUtils.getContext().getBean(UserAuthService.class);
              }
              String requestAPI = getPathWithinApplication(request);
              System.out.println("访问接口:" + requestAPI);
      
              Subject subject = SecurityUtils.getSubject();
              // 判断访问接口是否需要过滤(数据库中是否有对应信息)
              boolean needFilter = userAuthService.needFilter(requestAPI);
              if (!needFilter) {
                  return true;
              } else {
                  // 判断当前用户是否有相应权限
                  boolean hasPermission = false;
                  try {
                      String username = subject.getPrincipal().toString();
                      Set<String> permissionAPIs = userAuthService.getUserPermission(userService.getUserByName(username).getId());
                      for (String api : permissionAPIs) {
                          if (api.equals(requestAPI)) {
                              hasPermission = true;
                              break;
                          }
                      }
      
                      if (hasPermission) {
                          return true;
                      } else {
                          throw new PermissionException("您没有该权限!");
                      }
                  }catch (NullPointerException e){
                      throw new Exception("空指针异常");
                  }
              }
          }
      }
      
    2. SpringContextUtils
      @Component
      public class SpringContextUtils implements ApplicationContextAware {
          private static ApplicationContext context;
      
          public void setApplicationContext(ApplicationContext context) throws BeansException {
              SpringContextUtils.context = context;
          }
      
          public static ApplicationContext getContext() {
              return context;
          }
      }
      
    展开全文
  • 传统的手机APP应用注册通常需要用户...但由于第三方登录往往不能提供手机号,所以部分采用第三方登录一般都让用户补全手机号等信息。总的来说传统的用户验证方式适合特定时期用户需求,现如今随着各类APP应用越来越...

    传统的手机APP应用注册通常需要用户输入用户名,填写用户密码,同时通过获取验证码绑定手机号。用户一旦注册后再次登录传统的方式都是提供用户名加密码,或者凭手机验证码登录。当然现在许多APP为了获取更多的用户也有部分采取第三方登录如微信。但由于第三方登录往往不能提供手机号,所以部分采用第三方登录一般都让用户补全手机号等信息。总的来说传统的用户验证方式适合特定时期用户需求,现如今随着各类APP应用越来越多,许多用户注册APP都都用相同的用户名和密码,这样做的原因是APP应用众多无法一一记在密码。但如果都用相同的用户名和密码存在拖库撞库等风险。当下许多APP登录采用了短信验证码模式。但验证码存在被拦截,短信通道被调用的风险,同时费用高等特点。那么现在互联网安全账户验证新方式来了。它就是秒验产品,也叫一键登录、免密登录。具体介绍如下:

    一、原理。用户一键授权登录后,通过网关取号比对,并返回比对结果实现手机用户免密登录。整个过程仅需1.5秒,用户全程无感知!

    二、优势。

    1、防控恶意注册、拖库撞库、暴力破解等风险

    2、拦截薅羊毛、刷红包、投票等作弊行为

    3、识别设备牧场、模拟器等推广作弊行为

    4、监测拦截盗卡盗刷、套现洗钱等风险

    5、保护短信通道安全,防止恶意调用短信接口

    6、保护商业敏感数据,防御爬虫危险行为

    三、应用场景。各类需要登录注册的APP、小程序、H5页面等。

    四、秒验产品额外提供的功能。

    除了进行身份认证之外,秒验还将推出“二次号检测”功能,能查询当前用户的卡号是否属于“二次号”——即运营商由于号码资源有限而再次启用的原销户卡号。很多用户虽然已经办理了“销号”业务,但却没有将号码与服务账号解绑。

    对于一些对安全性和保密性要求比较高的服务提供商,比如金融类应用,“二次卡查询功能”相当重要。

    当运营商“二次发卡”之时,原来用户的账户可能会有风险。如果服务提供商能提前通过用户在网时间判断该用户是否更换手机号码,那么可以保证用户能在注销号码之后,权益不会受损,同时也能让重新使用该号码的用户不误收提示信息。

    展开全文
  • 如果做到 免密码认证登录 ?流程图: 操作流程简单介绍:在客户端生成公私钥,然后将公钥追加到服务器授权文件尾部,为什么是追加到尾部呢?因为这个授权文件里面会存放很多的授权公钥或者别的验证数据,自然是不能...
    • SSH-2 目前提供了 2 种常用的客户端认证方式。

      1、基于密码的客户端认证,使用账号和密码认证

      2、基于密钥的客户端认证,免密码认证

    • SSH-2 默认会优先尝试 密钥认证, 如果认证失败,才会尝试 密码认证

    • 如何做 免密码认证登录 ?流程图:

      操作流程简单介绍:在客户端生成公私钥,然后将公钥追加到服务器授权文件尾部,为什么是追加到尾部呢?因为这个授权文件里面会存放很多的授权公钥或者别的验证数据,自然是不能覆盖的,只能追加。

    操作流程

    1、生成公私钥,输入命令之后一路回车即可

    $ ssh-keygen
    
    dengzemiaodeMacBook-Pro:~ dengzemiao$ ssh-keygen
    Generating public/private rsa key pair.
    Enter file in which to save the key (/Users/dengzemiao/.ssh/id_rsa): 
    /Users/dengzemiao/.ssh/id_rsa already exists.
    // 如果之前有创建,这里会询问是否覆盖,根据自己情况决定,如果不想覆盖修改一下上面的路径即可
    Overwrite (y/n)? 
    

    2、查看公私钥,并找到该目录

    $ cd ~/.ssh
    
    dengzemiaodeMacBook-Pro:~ dengzemiao$ cd ~/.ssh
    dengzemiaodeMacBook-Pro:.ssh dengzemiao$ ls
    id_rsa	  id_rsa.pub	known_hosts
    
    // id_rsa:私钥文件
    // id_rsa.pub:公钥文件
    
    // 查看一下公钥
    dengzemiaodeMacBook-Pro:.ssh dengzemiao$ cat id_rsa.pub
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDjVE65ziQ/cAyjwS2+zcqGip6jzndh4dYKUsop0kYAfMSnKF3do1fbU903JB4jzbyICuF5oGCLknB2uIvxp/uk2BdrtstFNuiRqTyY4c/i0ZxsWkGhTOfbuWFzHBpZGuCFKEO4/y2BwDss7R5nlwcQ1tNaB9I5Ck8Uf3d85oqJKBRkVjxGUQz15AQtzvvQf9RIhWtefLJAvqWfZKS/5TAcsd9nyznLSAAbHMf/KlmbZ7ifE1QccCZNIAD7fw9WHYNVnNjRDDItoAhRsIm4bSdAWHW++wmUsVoJ6pt0D8fySqnhLLfSYBuEn16KQxooB1dBx4g7Rk5Ju90C5gtC1T95 dengzemiaovip@163.com
    

    3、将公钥发送到服务端(手机)存储

    $ ssh-copy-id root@10.0.89.184
    
    dengzemiaodeMacBook-Pro:~ dengzemiao$ cd ~/.ssh
    dengzemiaodeMacBook-Pro:.ssh dengzemiao$ ls
    id_rsa		id_rsa.pub	known_hosts
    dengzemiaodeMacBook-Pro:.ssh dengzemiao$ ssh-copy-id root@10.0.89.184
    /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/Users/dengzemiao/.ssh/id_rsa.pub"
    /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
    /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
    // 这里需要输入手机端 root 账户的密码确认
    root@10.0.89.184's password: 
    
    Number of key(s) added:        1
    
    Now try logging into the machine, with:   "ssh 'root@10.0.89.184'"
    and check to make sure that only the key(s) you wanted were added.
    

    4、然后我们设置输入之前的登录命令,就不需要在输入密码直接进入到服务端(手机)里面了。这里有个细节:就是我们在发送公钥的时候我们用的是 root 这个账户,那么另外一个 mobile 账户如果登录还是需要输入密码的,因为只配置了 root 账户,但是我们只需要用到 root 账户就够了。

    $ ssh root@10.0.89.184
    
    dengzemiaodeMacBook-Pro:~ dengzemiao$ ssh root@10.0.89.184
    iPhone:~ root# 
    

    5、查看我们发送到服务端(手机)的公钥,命令行按上面链接进入手机,查看到公钥之后可以跟上面客户端的进行对比。

    $ cd ~/.ssh
    
    dengzemiaodeMacBook-Pro:~ dengzemiao$ ssh root@10.0.89.184
    iPhone:~ root# cd ~/.ssh
    iPhone:~/.ssh root# ls
    authorized_keys
    iPhone:~/.ssh root# cat authorized_keys
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDjVE65ziQ/cAyjwS2+zcqGip6jzndh4dYKUsop0kYAfMSnKF3do1fbU903JB4jzbyICuF5oGCLknB2uIvxp/uk2BdrtstFNuiRqTyY4c/i0ZxsWkGhTOfbuWFzHBpZGuCFKEO4/y2BwDss7R5nlwcQ1tNaB9I5Ck8Uf3d85oqJKBRkVjxGUQz15AQtzvvQf9RIhWtefLJAvqWfZKS/5TAcsd9nyznLSAAbHMf/KlmbZ7ifE1QccCZNIAD7fw9WHYNVnNjRDDItoAhRsIm4bSdAWHW++wmUsVoJ6pt0D8fySqnhLLfSYBuEn16KQxooB1dBx4g7Rk5Ju90C5gtC1T95 dengzemiaovip@163.com
    

    这一章是智能操作这些步骤,下一章将手动操作一下这些步骤,以及如何将本地公钥远程拷贝到服务端尾部,如果我们正常使用,这章就够了。

    但是知道手动操作流程就好比知道智能操作的上一层做了哪些东西,思路大同小异,扩展学习一下。

    也知道一下怎么通过 ssh 远程拷贝文件,以及怎么处理文件权限的问题。

    展开全文
  • 用户手机号码验证是目前无线APP在用户注册、登录时必不可少的一个环节,而开发者在用户手机号码验证的方式抉择上,短信验证码貌似永远是第一选择。除了方案成熟、提供短信验证码的通信服务商多、价格便宜之外,短信...
  • Android-浅谈手机号一键免密登陆

    千次阅读 2018-10-18 12:10:08
    现在的登录基本上都用手机号,所以我们可以使用手机号一键登录(PS:注意!!!手机号不需要手动输入) 其实三大运营商早就支持了手机号一键登录,只是在其他APP里面不常见而已! 流程 具体的操作流程三大运营商基本...
  • 之前在一个项目中,需要实现短信快捷登录,当输入手机号获取验证码且验证码正确时,通过数据库查询出用户,而由于使用了shiro对密码进行了加密,导致查询出来的用户密码时加密的,不能够进行登录。 解决办法: 1....
  • 本项目 只获取用户手机号进行注册 注册完成后 可通过code 或openId直接进行免密登录 1. pom.xml引入微信SDK <!--微信miniapp SDK--> <dependency> <groupId>com.github.binarywang</...
  • 调用中国移动统一认证SDK返回103101 签名错误的原因是因为在统一认证的请求参数中的sign字段出现错误导致的,这个错误主要出现在开发者调用统一认证服务端api获取手机号时或者老版本的Android客户端sdk也有可能出现...
  • 手机号如何成为个人用户在移动互联网上的“虚拟身份证”?对于个人用户而言,是便捷;对于服务提供商而言,则是有据可循。
  • 一、传统APP手机注册登录验证的痛点。 ... 2、 传统手机绑定需要通过验证码验证手机真实性...手机号码一键登录可应用于一切注册和登录场景,为用户提供真正意义上的一键免密注册/登录,整个过程只需1.5秒,大幅提高用...
  • 我们在浏览器登录网站后如果换了一台新的设备就需要重新登录账号,但是这样就会导致账号被风控,需要重新输入账号密码甚至接收邮箱及手机号验证码。那么有什么方法和软件可以直接用买来的cookie(简称CK)账号导入到...
  • 免密认证

    2017-05-26 17:00:52
    免密认证是中国电信天翼账号推出一项互联网身份验证解决方案,依托运营商的移动数据网络,采用“通信网关取”及SIM卡识别等技术,准确识别用户手机号码。对于用户而言,使用免密认证的过程中,无需注册,只需点击...
  • csdn博客登录不上-why?

    2019-01-11 14:39:16
      标题距离上篇博客已有三月之余,今天登录csdn才发现登录成功之后,立马又退回了登录界面,试了好几次也是如此,然后试着用手机号免密登录也是如此。注册账号有一年左右了,没有更换过密码,还记得在注册的时候看...
  • 用户首次扫码进入,小程序自动获取用户手机号。 根据手机号注册成为贵单位APP平台用户(平台会返回唯一标识)。 用户记录表需要把贵单位APP平台的唯一标识记录下来。 贵单位需提供APP平台的注册接口(包含调用...
  • 最近项目上运用到了spring security来控制控制权限,然而钉钉端采用的前后端分离的模式进行开发,pc端未采用前后...2.钉钉端需要使用手机号码免密登录,pc端需要账号密码进行登录。 功能完成后,此处做个总结。 在Se...
  • 若依开源框架登录使用的配置大部分都是security自定义的,目前希望在此框架基础上支持自定义的登录,如手机号+密码登录认证、手机号+短信验证码认证。 1、自定义登录实现思路 主要是实现继承...
  • 一键登录优势何在

    2020-05-27 14:38:32
    在应用客户端中植入shareinstall三网认证的集成SDK后,即注册或登录阶段,在用户同意授权后即可完成本机号码免密登录,可以说是一种APP登录方式的革新。 一键登录的主要特点是以手机号码作为账号,无需验证,免密码...
  • 产品经理 - 登录 注册

    2016-10-23 20:08:00
    注册流程登录流程找回密码流程风控流程快速进行推广、进行个性...账号密码:账号密码登录:账号 密码全球手机登录:手机号 密码三方授权登录:三方账号 密码三方静默登录:三方账号 密码手机验证:免密登录手机号 ...
  • 在应用客户端中植入中国移动认证的集成SDK后,即注册或登录阶段,在用户同意授权后即可完成本机号码免密登录,可以说是一种APP登录方式的革新。 一键登录的主要特点是以手机号码作为账号,无需验证,免密码即可登录...
  • 如何注册CSDN博客

    2021-06-02 14:02:26
    浏览器输入,blog.csdn.net,然后点击注册 点击登录之后,选择免密登录 输入手机号和验证码,登录之后就可以写博客了
  • 有道云笔记登录问题

    2019-09-10 10:30:46
    我刚刚遇上有道云笔记登录bug,以下是过程: 打开电脑端有道云笔记,提示要重新登录,我用手机号登进去后一片空白,啥都没了,并且给我生成的... 赶快看手机端,东西还在,但提示免密登录过期,让重新登录。 我...
  • 对于手机用户来说,身份验证是个必不可...由于手机号码实名认证工作已基本完成,手机号码愈发成为用户网络身份的唯一标识,免密认证正在成为登录优化的大势所趋。具体来看一下几种登录方式。账号密码登录先来说账号...
  • Shiro免密码登录

    千次阅读 2018-01-30 17:16:00
    最近遇到的需求,实现手机号+验证码登录,验证码能够通过查数据库校验,但是密码是加密过的对不上,需要免密登录,所以写一下帮助后人 1.shiro的配置文件里面有一个是<bean id="credentialsMatcher" class=...
  • 若依开源框架登录使用的配置大部分都是security自定义的,目前希望在此框架基础上支持自定义的登录,如手机号+密码登录认证、手机号+短信验证码认证。 1、自定义登录实现思路 主要是实现继承...
  • 半藏商城之前的登录只是普通的手机号,密码,验证码进行登录,并不支持手机验证码免密登录,刘苏墨(感谢哈)建议我加入手机验证码直接登录功能,正好有这个实力,安排上了。接下来分享一下我的手机短信验证码实现...
  • 遇到提交appstrore审核的问题,我们的app只有免密登录手机+验证码),没有账号加密码登录, 但是苹果需要提供一组登录的测试账号,但是我们并没有这样的入口。 请教一下各位有相关经验的朋友,这个该如何解决?

空空如也

空空如也

1 2 3
收藏数 41
精华内容 16
关键字:

手机号免密登录