谷粒学院——Day13【微信扫描登录】

news2024/11/17 1:37:37

OAuth2

OAuth2的使用场景

一、OAuth2解决什么问题

1. OAuth2提出的背景

照片拥有者想要在云冲印服务上打印照片,云冲印服务需要访问云存储服务上的资源。
在这里插入图片描述
 

2. 图例

资源拥有者:照片拥有者。
客户应用:云冲印。
受保护的资源:照片。
在这里插入图片描述
 

3. 方式一:用户名密码复制

适用于同一公司内部的多个系统,不适用于不受信的第三方应用。
在这里插入图片描述
 

4. 方式二:通用开发者key

适用于合作商或者授信的不同业务部门之间。
在这里插入图片描述
 

5. 方式三:办法令牌

接近OAuth2方式,需要考虑如何管理令牌、颁发令牌、吊销令牌,需要统一的协议,因此就有了OAuth2协议。
在这里插入图片描述
 


二、现代微服务安全

除了开放系统授权,OAuth2还可以应用于现代微服务安全。

1. 传统单块应用的安全

在这里插入图片描述
 

2. 现代微服务安全

现代微服务中系统微服务化以及应用的形态和设备类型增多,不能用传统的登录方式。
核心的技术不是用户名和密码,而是token,由AuthServer颁发token,用户使用token进行登录。
在这里插入图片描述
 

3. 典型的OAuth2应用

在这里插入图片描述
 


三、总结

在这里插入图片描述
 


四、OAuth2最简向导

川崎高彦:OAuth2领域专家,开发了一个OAuth2 sass服务,OAuth2 as Service,并且做成了一个公司。
再融资的过程中为了向投资人解释OAuth2是什么,于是写了一篇文章,《OAuth2最简向导》。


二、OAuth2的正式定义

一、什么是OAuth2

1. OAuth2正式定义

在这里插入图片描述
 

2. 令牌的核心

在这里插入图片描述
 

3. OAuth2的历史

在这里插入图片描述
 

4. OAuth2的优势

在这里插入图片描述
 

5. OAuth2的不足

在这里插入图片描述
 

6. Auth2涉及的角色

在这里插入图片描述

 

7. OAuth2术语

在这里插入图片描述
在这里插入图片描述

 

8. OAuth2令牌的类型

在这里插入图片描述
 

9. OAuth2的误解

在这里插入图片描述
 


二、回顾

在这里插入图片描述
 


微信扫描登录

一、生成授权URL

一、准备工作

  • 熟悉微信登录流程
    参考文档:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=e547653f995d8f402704d5cb2945177dc8aa4e7e&lang=zh_CN

  • 获取access_token时序图
    在这里插入图片描述
     


二、后端开发

1. 添加配置

application.properties添加相关配置信息:

# 微信开放平台 appid
wx.open.app_id=你的appid
# 微信开放平台 appsecret
wx.open.app_secret=你的appsecret
# 微信开放平台 重定向url
wx.open.redirect_url=http://你的服务器名称/api/ucenter/wx/callback

2. 创建常量类

创建 util 包,创建 ConstantWxUtils.java 常量类:

@Component
public class ConstantWxUtils implements InitializingBean {
    @Value("${wx.open.app_id}")
    private String appID;

    @Value("${wx.open.app_secret}")
    private String appSecret;

    @Value("${wx.open.redirect_url}")
    private String redirectUrl;

    public static String WX_APP_ID;
    public static String WX_APP_SECRET;
    public static String WX_REDIRECT_URL;

    @Override
    public void afterPropertiesSet() throws Exception {
        WX_APP_ID=this.appID;
        WX_APP_SECRET=this.appSecret;
        WX_REDIRECT_URL=this.redirectUrl;
    }

}

3. 创建controller

@Controller //注意这里没有配置 @RestController
@CrossOrigin
@RequestMapping("/api/ucenter/wx")
public class WxApiController {

    //生成微信扫描二维码,   %s 相当于?占位符
    @GetMapping("/login")
    public String getWxCode(){
        String baseUrl ="https://open.weixin.qq.com/connect/qrconnect"
                +"?appid=%s"
                +"&redirect_uri=%s"
                +"&response_type=code"
                +"&scope=snsapi_login"
                +"&state=%s"
                +"#wechat_redirect";

        //对redirect_uri进行URLEncoder编码
        String redirect_uri = ConstantWxUtils.WX_REDIRECT_URL;
        try {
            //参数1:待编码字符串 参数2:编码方式
            redirect_uri = URLEncoder.encode(redirect_uri, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        //设置 %s 占位符的参数,上面有3处
        String url = String.format(baseUrl,
                ConstantWxUtils.WX_APP_ID,
                redirect_uri,
                "atguigu");


        //请求微信地址
        return "redirect:" + url;
    }
}

授权url参数说明:

参数是否必须说明
appid应用唯一标识
redirect_uri请使用urlEncode对链接进行处理
response_type填code
scope应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login即
state用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验

4. 测试

访问:http://localhost:8160/api/ucenter/wx/login
访问授权url后会得到一个微信登录二维码:

 
用户扫描二维码会看到确认登录的页面:
在这里插入图片描述
 
用户点击“确认登录”后,微信服务器会向谷粒学院的业务服务器发起回调,因此接下来我们需要开发回调controller。
 


二、开发回调URL

一、准备工作

1. 全局配置的跳转路径

# 微信开放平台 重定向url
wx.open.redirect_url=http://回调地址/api/ucenter/wx/callback

2. 修改当前项目启动端口号为8160

3. 测试回调是否可用

WxApiController 中添加方法:

 @GetMapping("/callback")
    public String callback(String code, String state, HttpSession session){
        //得到授权临时票据code
        System.out.println("code = " + code);
        System.out.println("state = " + state);
        return "redirect:http://localhost:3000";
    }

生成微信二维码后,手机扫码点击确认后在控制台会打印出获取到的扫码人的信息:
在这里插入图片描述
 


二、后台开发

1. 添加依赖

<dependencies>
    <!--httpclient-->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
    </dependency>
    <!--commons-io-->
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
    </dependency>
    <!--gson-->
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
    </dependency>
</dependencies>

2. 创建httpclient工具类

HttpClientUtils

public class HttpClientUtils {

    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);
            }
            // 设置参数
            RequestConfig.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 = HttpClientUtils.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 = HttpClientUtils.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 = HttpClientUtils.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();
        }
    }

}

3. 创建回调controller方法

@Controller //注意这里没有配置 @RestController
@CrossOrigin
@RequestMapping("/api/ucenter/wx")
public class WxApiController {

    @Autowired
    private UcenterMemberService ucenterMemberService;

    //2.获取扫描人信息,添加数据
    @GetMapping("/callback")
    public String callback(String code, String state, HttpSession session){
        //得到授权临时票据code
//        System.out.println("code = " + code);
//        System.out.println("state = " + state);

        //获取code值,临时票据,类似于验证码

        //拿着code,去请求微信固定的地址,得到两个值 access_token 和 openid
        String baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token"+
                "?appid=%s" +
                "&secret=%s" +
                "&code=%s" +
                "&grant_type=authorization_code";

        //拼接三个参数:id 秘钥 和 code值
        String accessTokenUrl = String.format(baseAccessTokenUrl,
                ConstantWxUtils.WX_APP_ID,
                ConstantWxUtils.WX_APP_SECRET,
                code);


        //请求上面拼接好的地址,得到两个值 access_token 和 openid
        //使用httpclient【不用浏览器,也能模拟器出浏览器的请求和响应过程】发送请求,得到返回的结果
        String accessTokenInfo = null;
        try {
            accessTokenInfo = HttpClientUtils.get(accessTokenUrl);
            System.out.println("accessTokenInfo:" +accessTokenInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }

        //从accessTokenInfo中获取出  access_token 和 openid 的值
        //将 accessTokenInfo 转换成 map集合,根据map的key 就可以获取对应的value
        //使用json转换工具
        Gson gson = new Gson();
        HashMap mapAccessToken = gson.fromJson(accessTokenInfo, HashMap.class);
        String access_token = (String) mapAccessToken.get("access_token");
        String openid = (String) mapAccessToken.get("openid");

        //判断数据库是否存在相同的微信内容,根据openid判断
        UcenterMember member = ucenterMemberService.getMemberByOpenId(openid);

        if (member == null) {

            //拿着 access_token 和 openid 的值再去请求微信提供的固定地址
            //访问微信的资源服务器,获取用户信息
            String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
                    "?access_token=%s" +
                    "&openid=%s";
            String userInfoUrl = String.format(baseUserInfoUrl, access_token, openid);

            String resultUserInfo = null;
            try {
                resultUserInfo = HttpClientUtils.get(userInfoUrl);
                System.out.println(resultUserInfo);
            } catch (Exception e) {
                e.printStackTrace();
            }

            HashMap<String, Object> userInfoMap = gson.fromJson(resultUserInfo, HashMap.class);

            String nickname = (String) userInfoMap.get("nickname"); // 昵称
            String headimgurl = (String) userInfoMap.get("headimgurl"); // 头像


            //向数据库插入一条记录
            member = new UcenterMember();
            member.setNickname(nickname);
            member.setAvatar(headimgurl);
            member.setOpenid(openid);
            ucenterMemberService.save(member);

        }

        //使用jwt根据member对象生成token字符串
        String jwtToken = JwtUtils.getJwtToken(member.getId(), member.getNickname());

        // 返回首页面
        return "redirect:http://localhost:3000?token="+jwtToken;
    }


    //1. 生成微信扫描二维码
    @GetMapping("/login")
    public String getWxCode(){
        String baseUrl ="https://open.weixin.qq.com/connect/qrconnect"
                +"?appid=%s"
                +"&redirect_uri=%s"
                +"&response_type=code"
                +"&scope=snsapi_login"
                +"&state=%s"
                +"#wechat_redirect";

        //对redirect_uri进行URLEncoder编码
        String redirect_uri = ConstantWxUtils.WX_REDIRECT_URL;
        try {
            //参数1:待编码字符串 参数2:编码方式
            redirect_uri = URLEncoder.encode(redirect_uri, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        //设置 %s 占位符的参数,上面有3处
        String url = String.format(baseUrl,
                ConstantWxUtils.WX_APP_ID,
                redirect_uri,
                "atguigu");


        //请求微信地址
        return "redirect:" + url;

    }

}

4. 业务层

UcenterMemberService:

public interface UcenterMemberService extends IService<UcenterMember> {

    // 登录的方法
    String login(LoginVo loginVo);

    // 注册的方法
    void register(RegisterVo registerVo);

    UcenterMember getMemberByOpenId(String openid);
}

UcenterMemberServiceImpl:

 @Override
    public UcenterMember getMemberByOpenId(String openid) {
        QueryWrapper<UcenterMember> wrapper = new QueryWrapper<>();
        wrapper.eq("openid", openid);
        UcenterMember member = baseMapper.selectOne(wrapper);
        return member;
    }

5. 测试

在这里插入图片描述
 
在这里插入图片描述
 


三、前端整合和显示用户登录信息

1. 修改default.vue页面脚本

<script>
import "~/assets/css/reset.css";
import "~/assets/css/theme.css";
import "~/assets/css/global.css";
import "~/assets/css/web.css";

import loginApi from "@/api/login"
import cookie from "js-cookie";

export default {
  data() {
    return {
      token: "",
      loginInfo: {
        id: "",
        age: "",
        avatar: "",
        mobile: "",
        nickname: "",
        sex: "",
      }
    }
  },
  created() {

    //获取路径中token的值【用于微信二维码登录】
    this.token = this.$route.query.token
    if (this.token) {
      //判断路径中是否有token值
      this.wxLogin()
    }
  
    this.showInfo()
  },
  methods: {

    //微信登录显示的方法
    wxLogin() {
      //把token值放到cookie里面
      cookie.set("guli_token", this.token, { domain: "localhost" })
      cookie.set("guli_ucenter", "", { domain: "localhost" })

      //调用接口,根据token获取用户信息
      loginApi.getLoginUserInfo()
        .then(response => {
            this.loginInfo = response.data.data.userInfo
            cookie.set("guli_ucenter", this.loginInfo, { domain: "localhost" })
        })


    },

    // 退出登录
    logout() {
      //清空cookie值
      cookie.set("guli_token", "", {domain: "localhost"})
      cookie.set("guli_ucenter", "", {domain: "localhost"})

      //跳转首页面
      window.location.href = "/";
    },

    //创建方法从cookie中获取信息
    showInfo() {
      //从cookie中获取信息
      var userStr = cookie.get("guli_ucenter");

      //转字符串转换成json对象(js对象)
      if (userStr) {
        this.loginInfo = JSON.parse(userStr);
      }
    }
  }
};
</script>

2. 测试

访问:http://localhost:8160/api/ucenter/wx/login

扫描进行确认,会在首页显示扫码人的信息:
在这里插入图片描述


 
创作不易,如果有帮助到你,请给文章点个赞和收藏,让更多的人看到!!!
关注博主不迷路,内容持续更新中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/113642.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python pandas库|任凭弱水三千,我只取一瓢饮(2)

上一篇链接&#xff1a; Python pandas库&#xff5c;任凭弱水三千&#xff0c;我只取一瓢饮&#xff08;2&#xff09;_Hann Yang的博客-CSDN博客 I~Q&#xff1a; Function10~25 Types[Function][9:25] [infer_freq, interval_range, isna, isnull, json_normalize, lres…

④【Maven】Maven的构建命令

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ Maven的构建命令一、注意二、&#x1f680;清理…

指针与数组的联系与区别【一万六千字超详解】

&#x1f3d6;️作者&#xff1a;malloc不出对象 ⛺专栏&#xff1a;《初识C语言》 &#x1f466;个人简介&#xff1a;一名双非本科院校大二在读的科班编程菜鸟&#xff0c;努力编程只为赶上各位大佬的步伐&#x1f648;&#x1f648; 目录前言数组的性质1.1 数组的内存布局1…

第四章 Spring的基础用法

文章目录 Spring的起源和背景理解依赖注入Spring容器理解Spring容器中的Bean管理容器中的Bean及其依赖注入自动装配使用Java类进行配置管理使用静态工厂、实例工厂创建Bean实例抽象Bean与子Bean容器中的工厂Bean管理Bean的生命周期几种特殊的依赖注入Spring的简化配置SpEL的功…

kali中间人攻击

数据来源 一、中间人攻击原理 1. 利用的ARP协议的漏洞 2. ARP协议原理&#xff1a; 1&#xff09;发送ARP广播请求目标MAC地址 2&#xff09;目标主机发送ARP单播应答&#xff0c;响应MAC地址 3. ARP攻击原理 攻击人通过发送虚假的ARP应答实现ARP缓存投毒!而受害人没有办法进行…

文件存储案例

1.文件存储-File文件存储案例 1.1.案例要求 1.2参考代码 文件读取 百度安全验证 文件最终的保存的目录在/data/data/user/0/包/files下&#xff08;1&#xff09;布局文件 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android&q…

kubernetes中使用Service反向代理外部服务

当我们的某个服务在外部集群的时候&#xff0c;但是又想k8s集群内的应用连接它&#xff0c;这是可以创建一个service&#xff0c;用service代理外部服务&#xff0c;然后集群内就能连接该service&#xff0c;从而间接的访问外部服务。 创建一个service代理外部的服务 创建一个…

代码挑战画 魔法圣诞树

一、前言 本文会基于C# GDI技术 从零到一 实现一颗 魔法圣诞树&#xff01;源码和素材在文末全部都有&#xff01; 二、魔法圣诞树 对于用代码画圣诞树&#xff0c;网上各种编程语言像python、css、java、c/c我们都有见到过了&#xff0c;那么在绘图方面&#xff0c;还有一位…

FastDDS(6)核心库综述

Fast DDS(前身为Fast RTPS)是DDS规范的高效高性能实现,DDS规范是一种用于分布式应用软件的以数据为中心的通信中间件(DCPS)。本次回顾Fast DDS的体系结构、操作和关键特性。 架构 Fast DDS的架构如下图所示,其中可以看到具有以下不同环境的层模型。 Application layer应…

人员工装未穿戴识别检测 opencv

人员工装未穿戴识别检测基于OpenCvyolo计算机视觉深度学习技术对现场画面中人员行为着装穿戴实时监测识别&#xff0c;发现不按要求着装违规行为立即抓拍存档同步后台。OpenCV-Python使用Numpy&#xff0c;这是一个高度优化的数据库操作库&#xff0c;具有MATLAB风格的语法。所…

RabbitMQ 第一天 基础 1 MQ的基本概念 1.4 MQ 的劣势 1.5 常见的MQ 产品

RabbitMQ 【黑马程序员RabbitMQ全套教程&#xff0c;rabbitmq消息中间件到实战】 文章目录RabbitMQ第一天 基础1 MQ的基本概念1.4 MQ 的劣势1.4.1 MQ 的劣势1.4.2 小结1.5 常见的MQ 产品第一天 基础 1 MQ的基本概念 1.4 MQ 的劣势 1.4.1 MQ 的劣势 从远程调用 到 利用 MQ 作…

css实现九宫格

首先是实现九宫格的样式&#xff0c;对每一行进行偏移&#xff0c;当鼠标放上去会使他们形成一张图片。 html <div class"img_container"><div class"img1"></div><div class"img1"></div><div class"i…

2022年,来者犹可追

始料未及的是&#xff0c; 疫情持续到了2022年。好在“大疫不过三年”&#xff0c;只不过是结束来的同样措不及防&#xff0c;全家的一次高烧免疫&#xff0c;没有朋友圈中的云淡风轻&#xff0c;冷暖自知&#xff0c;希望明年能够拥有平安喜乐的时光。回首这一年&#xff0c;“…

kotlin与java实现混编基础看这篇就够了

前几年一直关注安卓&#xff0c;想换个方向&#xff0c;奔着移动端大步向前&#xff0c;由于比较懒就一直停留在想法&#xff0c;这不今天勤快点&#xff0c;动手搞了一个基础的java和kotlin混编&#xff0c;和大家总结分享一下。 首先需要了解什么事kotlin&#xff0c;kotlin…

如何使用腾讯云轻量应用服务器挂载 CFS 文件系统

文件存储&#xff08;Cloud File Storage&#xff0c;CFS&#xff09;提供了可扩展的共享文件存储服务&#xff0c;可与腾讯云云服务器 、容器、批量计算、轻量应用服务器等服务搭配使用。CFS 提供了标准的 NFS 及 CIFS/SMB 文件系统访问协议&#xff0c;可为计算服务提供共享的…

【Unity】【Pico】手柄摇杆控制第一人称移动和旋转

【Unity】【Pico】手柄摇杆控制第一人称移动和旋转 背景&#xff1a;开发影院系统 环境&#xff1a;Unity2021.3、PicoNeo3ProEye 描述&#xff1a;已经在Unity项目中实现第一人称WASD移动和鼠标旋转&#xff08;代码见我的其他博文&#xff09; 需求&#xff1a;希望项目在Pi…

Cobalt Strike Beacon 初探

背景 RTO I 的课程结束了&#xff0c;Cobalt Strike 算是会用了。然后继上一篇文章之后&#xff0c;我还没有机会用 Cobalt Strike Beacon 做一下 Windows Defender Bypass。之后会写。 另外&#xff0c;我也想问一下我自己&#xff0c;Cobalt Strike 里面最基本的 payload -…

Springboot+Netty实现基于天翼物联网平台CTWing(AIOT)终端TCP协议(透传模式)-应用订阅端(北向应用)

之前实现了使用SpringbootNetty基于天翼物联网平台CTWing(AIOT)终端TCP协议(透传模式)-设备终端&#xff08;南向设备&#xff09;&#xff0c;模拟设备发送的数据给到了AIOT平台&#xff0c;那么在第三方应用也需要去订阅AIOT平台的数据&#xff0c;以及对设备进行下发指令(消…

FastGithub的下载和使用

前言 github访问很不稳定&#xff0c;时断时续&#xff0c;有时候根本打不开&#xff01; 下载 方式一&#xff1a;官方地址下载&#xff08;有及时更新&#xff09; FastGithub1.1.7下载、FastGithub2.1.4_windows、FastGithub2.1.4_Linux、 更多 方式二&#xff1a;本地上传…

[编程语言][C++][Qt]单独添加UI文件

单独添加UI文件问题描述解决方案1. 添加UI文件2. 与对应的界面类进行关联3. 修改UI文件4. 设置界面类读取UI文件总结问题描述 不知什么原因&#xff0c;Qt Creator并不是很完美很智能。当先写好界面类的头文件和源代码文件后&#xff0c;我们再添加用于可视化界面设计的UI文件…