• SpringCloud微服务实战系列(十九)Ouath2在真实场景中的应用之客户端接入(第一种写法)
    date_range 2020-05-12 14:33:50
    folder SpringCloud专题
    person 陈付菲 公开
    thumb_up 点赞4
    remove_red_eye 围观976

    SpringCloud微服务实战系列(十九)Ouath2在真实场景中的应用之客户端接入(第一种写法)

    一、概述

    《SpringCloud微服务实战系列(十七)Ouath2在真实场景中的应用之资源服务器》]中 已经介绍了资源服务器是如何搭建的。

    《SpringCloud微服务实战系列(十八)Ouath2在真实场景中的应用之授权服务器》]中 已经介绍了授权服务器是如何搭建的。

    本篇就是对Oauth2的实际应用方法的客户端接入方式的其中一种方法进行介绍。这种方法跟另外一种的区别是:

    1. 可以配置用户信息查询地址并自动查询补入。
    2. Nginx转发未携带请求host则会出错

    如果大家正在寻找一个java的学习环境,或者在开发中遇到困难,可以加入我们的java学习圈,点击即可加入,共同学习,节约学习时间,减少很多在学习中遇到的难题。

    在Spring Oauth2中,Oauth2的使用过程中将角色分为三种:ResourceServer,AuthorizationServer,OauthClient.

    由于篇幅较大,这里将Oauth2的搭建分成三个部分。本篇介绍OauthClient的其中一种写法。

    这种方式是基于spring-security-oauth2-client的自动化配置。在Springboot官方文档可以找到这种配置方法。https://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/html/boot-features-security.html#boot-features-security-oauth2

    代码可以在https://www.pomit.cn/java/spring/springcloud.html中的Oauth2相关中的组件下载即可。

    二、客户端接入

    客户端接入是一个复杂的过程,按照Springboot官方文档的指引,我这里把完整的流程写出来。

    下面讲述下这个过程是怎样的。

    2.1 引入依赖

    需要引入spring-boot-starter-web、spring-cloud-starter-security和spring-security-oauth2-client相关jar包.

    依赖如下:

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-client</artifactId>
        </dependency>
    </dependencies>

    2.2 配置文件

    这里使用yaml文件写配置,配置文件application.yml:

    application.yml:

    server:
       port: 8181
    spring:
       profiles:
          active: loc
       application:
          name: oauthClient
    logging:
       level:
          root: info

    这里

    1. 应用名称为oauthClient
    2. 指定配置为loc。

    application-loc.yml:

    env: loc
    
    spring:
       security:
          oauth2:
             client:
                registration:
                   oauthClient:
                      clientId: MwonYjDKBuPtLLlK
                      clientSecret: 123456
                      clientName: oauthClient
                      provider: oauthAuth
                      authorizationGrantType: authorization_code
                      redirectUriTemplate: http://tw.pomit.cn/custom-callback
                provider:
                   oauthAuth:
                      tokenUri: http://sso.pomit.cn/oauth/token
                      authorizationUri: http://sso.pomit.cn/oauth/authorize
                      userInfoUri: http://res.pomit.cn/api/userInfo
                      userNameAttribute: data

    这里配置的东西可能会让你产生疑惑,下面一一讲述:

    1. spring.security.oauth2.client.registration.oauthClient是客户端的配置,其中最后的后缀oauthClient是你的应用名,千万别照搬了。clientId和clientSecret是客户端的密钥,需要在授权服务器加上这个客户端,provider指的是授权服务器,authorizationGrantType是授权类型,redirectUriTemplate是回调地址,授权服务器授权成功要有回调地址的。
    2. spring.security.oauth2.client.provider.oauthAuth是关于授权服务器的配置,其中最后的后缀oauthAuth是你的授权服务器应用名,千万别照搬了。tokenUri是token获取地址,后缀基本上都是/oauth/token;authorizationUri是授权地址,后缀基本上都是/oauth/authorize;userInfoUri是获取用户信息接口,这个要配置资源服务器的地址,是自己定义的,userNameAttribute是参数字段名。

    基本配置就是这样了,如果中间出现问题,要多试几次查找问题。

    2.3 启动

    使用main直接启动即可。无需其他配置。

    OauthClientApplication:

    package cn.pomit.springbootwork.oauthclient;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class OauthClientApplication {
        public static void main(String[] args) {
            SpringApplication.run(OauthClientApplication.class, args);
        }
    
    }

    2.4 安全控制配置

    这个安全控制,只是普通的Spring Security的安全配置,外加一行oauth2的配置。

    需要继承WebSecurityConfigurerAdapter,并加上@EnableWebSecurity。

    AccessSecurityConfiguration如下:

    package cn.pomit.springbootwork.oauthclient.config;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    
    @Configuration
    @EnableWebSecurity
    public class AccessSecurityConfiguration extends WebSecurityConfigurerAdapter {
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
            .authorizeRequests()
                .mvcMatchers("/test/**").permitAll()
                .antMatchers("/").permitAll()
                .antMatchers("/index.html").permitAll()
                .antMatchers("/css/**").permitAll()
                .antMatchers("/js/**").permitAll()
                .antMatchers("/img/**").permitAll()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated().and()
                .oauth2Login().redirectionEndpoint()
                .baseUri("/custom-callback");
        }
    }

    其中, .oauth2Login().redirectionEndpoint().baseUri("/custom-callback");是表明了oauth2的授权回调地址。

    2.5 测试web

    这里写了三个web接口,来测试不用的访问控制级别的返回信息。

    OauthTestRest:

    package cn.pomit.springbootwork.oauthclient.web;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import cn.pomit.springbootwork.oauthclient.model.ResultModel;
    
    @Controller
    @RequestMapping("/")
    public class OauthTestRest {
    
        @ResponseBody
        @RequestMapping(value = "/test/test", method = { RequestMethod.GET })
        public ResultModel test() {
    
            return ResultModel.ok("我就是test,客户端");
        }
    
        @RequestMapping(value = "/", method = { RequestMethod.GET })
        public String index() {
    
            return "/index.html";
        }
    
        @RequestMapping(value = "/logTo", method = { RequestMethod.GET })
        public String logTo() {
    
            return "/index.html";
        }
    
    }
    

    OauthClientRest:

    package cn.pomit.springbootwork.oauthclient.web;
    
    import java.security.Principal;
    
    import javax.servlet.http.HttpServletRequest;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import cn.pomit.springbootwork.oauthclient.model.IpModel;
    import cn.pomit.springbootwork.oauthclient.model.ResultModel;
    import cn.pomit.springbootwork.oauthclient.util.IPUtil;
    
    @RestController
    @RequestMapping("/api")
    public class OauthClientRest {
    
        @RequestMapping(value = "/ip", method = { RequestMethod.GET })
        public ResultModel ip(HttpServletRequest request) {
            IpModel ipModel = new IpModel();
            ipModel.setClientIpAddress(IPUtil.getIpAddr(request));
            ipModel.setServerIpAddress(IPUtil.localIp());
            return ResultModel.ok(ipModel);
        }
    
        @RequestMapping(value = "/test")
        public ResultModel test(Principal principal) {
    
            return ResultModel.ok(principal.getName());
        }
    
        @RequestMapping(value = "/userInfo")
        public ResultModel userinfo(Principal principal) {
    
            return ResultModel.ok(principal.getName());
        }
    }
    

    OauthAdminRest:

    package cn.pomit.springbootwork.oauthclient.web;
    
    import java.security.Principal;
    
    import javax.servlet.http.HttpServletRequest;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import cn.pomit.springbootwork.oauthclient.model.IpModel;
    import cn.pomit.springbootwork.oauthclient.model.ResultModel;
    import cn.pomit.springbootwork.oauthclient.util.IPUtil;
    
    @RestController
    @RequestMapping("/admin")
    public class OauthAdminRest {
    
        @RequestMapping(value = "/ip", method = { RequestMethod.GET })
        public ResultModel ip(HttpServletRequest request) {
            IpModel ipModel = new IpModel();
            ipModel.setClientIpAddress(IPUtil.getIpAddr(request));
            ipModel.setServerIpAddress(IPUtil.localIp());
            return ResultModel.ok(ipModel);
        }
    
        @RequestMapping(value = "/test")
        public ResultModel test(Principal principal) {
    
            return ResultModel.ok(principal.getName());
        }
    
        @RequestMapping(value = "/userInfo")
        public ResultModel userinfo(Principal principal) {
    
            return ResultModel.ok(principal.getName());
        }
    }
    

    2.6 过程中用到的其他实体和工具

    IpModel :

    package cn.pomit.springbootwork.oauthclient.model;
    
    public class IpModel {
        private String clientIpAddress;
        private String serverIpAddress;
    
        public String getClientIpAddress() {
            return clientIpAddress;
        }
    
        public void setClientIpAddress(String clientIpAddress) {
            this.clientIpAddress = clientIpAddress;
        }
    
        public String getServerIpAddress() {
            return serverIpAddress;
        }
    
        public void setServerIpAddress(String serverIpAddress) {
            this.serverIpAddress = serverIpAddress;
        }
    
    }
    

    IPUtil:

    package cn.pomit.springbootwork.oauthclient.util;
    
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    
    import javax.servlet.http.HttpServletRequest;
    
    public class IPUtil {
        /**
         * @Description: 获取客户端IP地址
         */
        public static String getIpAddr(HttpServletRequest request) {
            String ip = request.getHeader("x-forwarded-for");
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
                if (ip.equals("127.0.0.1")) {
                    // 根据网卡取本机配置的IP
                    InetAddress inet = null;
                    try {
                        inet = InetAddress.getLocalHost();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    ip = inet.getHostAddress();
                }
            }
            // 多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
            if (ip != null && ip.length() > 15) {
                if (ip.indexOf(",") > 0) {
                    ip = ip.substring(0, ip.indexOf(","));
                }
            }
            return ip;
        }
    
        /**
         * 获取的是本地的IP地址
         * 
         * @return
         */
        public static String localIp() {
            String result = "";
            try {
                InetAddress address = InetAddress.getLocalHost();
                result = address.getHostAddress();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
            return result;
        }
    }
    

    ResultModel:

    package cn.pomit.springbootwork.oauthclient.model;
    
    /**
     * @author cff
     */
    public class ResultModel {
        private String errorCode;
        private String message;
        private Object data;
    
        public ResultModel() {
    
        }
    
        public ResultModel(String errorCode, String message) {
            this.errorCode = errorCode;
            this.message = message;
        }
    
        public ResultModel(String errorCode, String message, Object data) {
            this.errorCode = errorCode;
            this.message = message;
            this.data = data;
        }
    
        public String getErrorCode() {
            return errorCode;
        }
    
        public void set    ErrorCode(String errorCode) {
            this.errorCode = errorCode;
        }
    
        public String getMessage() {
            return message;
        }
    
        public void setMessage(String message) {
            this.message = message;
        }
    
        public Object getData() {
            return data;
        }
    
        public void setData(Object data) {
            this.data = data;
        }
    
        public static ResultModel ok(String testValue) {
            ResultModel rm = new ResultModel();
            rm.setData(testValue);
            return rm;
        }
    }
    

    三、测试过程

    资源服务器:http://res.pomit.cn
    授权服务器:http://sso.pomit.cn
    
    客户端:
    服务器1:http://tw.pomit.cn
    1. 未授权时:

    在这里插入图片描述

    1. 点击授权登录:

    在这里插入图片描述

    1. 如果已经授权过,则不会出现授权页面。否则出现授权登录页面:

    在这里插入图片描述

    1. 授权成功后,再点获取信息:

    在这里插入图片描述

    四、微信OAUTH2授权过程

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    品茗IT-博客专题:https://www.pomit.cn/lecture.html汇总了Spring专题Springboot专题SpringCloud专题web基础配置专题。

    快速构建项目

    Spring项目快速开发工具:

    一键快速构建Spring项目工具

    一键快速构建SpringBoot项目工具

    一键快速构建SpringCloud项目工具

    一站式Springboot项目生成

    Mysql一键生成Mybatis注解Mapper

    Spring组件化构建

    SpringBoot组件化构建

    SpringCloud服务化构建

    喜欢这篇文章么,喜欢就加入我们一起讨论SpringCloud使用吧! 品茗IT交流群

评论列表
mode_edit