OAuth2的入门理解和案例解析

OAuth2基本概念

        OAuth2全名为开放授权2.0(Open Authorization2.0);它是一个开放标准的授权协议;

用于授权于一个应用程序或服务访问用户在另一个应用程序中的资源,但能够无需提供

用户名和密码;例如我们现在常用的B站,它就能够通过微信,QQ等第三方实现用户登录

来进行用户操作;此时就以OAuth2协议来获取我们用户的基本信息;

OAuth2相关属性解析

        client_id/appid:客户端id。

        client_secret/secret:客户端密码或密钥。

        code:授权码;用来后续获取第三方的token。

        grant_type:选择的客户端授权模式;具体有四种模式;下面会简单介绍。

        redirect_uri:重定向地址。

        scope:用于限制应用程序对用户帐户的访问。应用程序可以请求一个或多个范围,然后该信息会在同意屏幕中呈现给用户,并且颁发给应用程序的访问令牌将仅限于授予的范围。

        access_token:我们所需要的申请令牌。

OAuth2的四种授权模式

授权码模式:用户先通过第三方应用向认证服务器申请授权码,再用授权码换取访问令牌;该模式安全性最高;

简化模式/隐式授权模式:用户直接通过第三方应用向认证服务器申请访问令牌,无需授权码。

其实就是没有授权码这中间步骤

密码模式:如果你高度信任某个第三方应用,可以将用户名和密码告诉该第三方应用,第三方应用拿到用户名和密码去申请授权获取令牌。 在这种模式中,用户必须把自己的密码给客户端。

客户端模式:第三方应用直接向认证服务器申请访问令牌,无需用户参与。


OAuth2授权码的流程解析

图片流程

文字解析:

(1)用户在客户端中选择了第三方登录

(2)此时资源服务器会重定向到对应的授权服务器去获取授权码;

    private final String REDIRECT_URI="http://127.0.0.1:9000/login/rcv_code";
    private final String CLIENT_ID="sobook";
    private final String SCOPE="all";
    private final String GRANT_TYPE="authorization_code";
    private final String CLIENT_SECRET="223344";

    @RequestMapping("/login/code")
    public String LoginCode(){
    //发出请求获取授权码
    String url = "http://127.0.0.1:8000/oauth/authorize?response_type=code" +
                "&client_id=" +CLIENT_ID+
                "&redirect_uri="+REDIRECT_URI+
                "&scope="+SCOPE;
        return "redirect:" +url;
}

(3)获取用户授权;用户输入对应的账号密码

(4)授权服务器校验成功后重定向返回授权码给资源服务器

@Configuration
@EnableAuthorizationServer  //放在过滤器的链条  
public class QqAuth2ServerConfig extends
        AuthorizationServerConfigurerAdapter {

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
       clients.inMemory()
         .withClient("sobook").secret(passwordEncoder.encode("223344"))//资源服务器的id和密钥
         .authorizedGrantTypes( "authorization_code")//授权模式为验证码
         .scopes("all")
         .autoApprove(true)
         .redirectUris("http://127.0.0.1:9000/login/rcv_code");//重定向地址
     }
}

(5)资源服务器通过授权码再次发送请求到授权服务器中获取token(请求令牌)

HttpRequest postRequest =
                HttpRequest.post("http://127.0.0.1:8000/oauth/token");
        postRequest.form("grant_type",GRANT_TYPE);
        postRequest.form("code",code);
        postRequest.form("client_id",CLIENT_ID);
        postRequest.form("client_secret",CLIENT_SECRET);
        postRequest.form("redirect_uri",REDIRECT_URI);
        //通过授权码获取token
        HttpResponse resp = postRequest.execute();
        String body = resp.body();//我们需要的token在body里面
        Map map = objectMapper.readValue(body, Map.class);//将字符串转成对象
        String token = (String) map.get("access_token");//获取token

(6)授权服务器校验成功后返回token给资源服务器

(7)资源服务器通过携带token再次发送请求到授权服务器中获取我们当前用户的基本信息与权限

     //通过token获取用户信息
        String url = "http://127.0.0.1:8000/api/info/getUser";
        HttpRequest postUser = HttpRequest.get(url).
                        header("Authorization","bearer "+token);
        String body1 = postUser.execute().body();
       

(8)授权服务器会将对应的用户信息和权限返回给资源服务器

    @GetMapping("/getUser")
    public Object getUser() {
        Object principal =
                SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        System.out.println("principal=" + principal);
        if (principal==null)  return null;
        if (principal instanceof UserDetails) {
            return (UserDetails) principal;
        } else {
            return String.valueOf(principal);
        }
    }

补充

        (1)在该例子中的client_id和client_secret都是我们自己手动创建的;在真正的项目当中我们使用OAuth2时需要向对应的第三方应用请求申请一下自己的client_id和client_secret.

        (2)所谓资源并非是我们资源服务器内Controller下的所有类;是要在我们资源服务器的声明类下所定义好的路径

@Configuration
@EnableResourceServer  //声明是资源服务器并且放在过滤器链条
public class ResourceServerConfig  extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.requestMatchers().antMatchers("/api/**")//定义以api开头的路由为资源
                .and()
                .authorizeRequests()
                .antMatchers("/api/adm/**").hasAuthority("adm")
                .antMatchers("/api/stu/**").hasAuthority("stu")
                .antMatchers("/api/**").authenticated();//authenticated已验证
    }

(3)在学习OAuth2中一定要理解什么是客户端,谁是第三方、哪些是资源;在不同的场景角度下

第三方的定义可能会有所不同;如对于微信来说,微信下的小程序应用就是第三方应用;而对于

小程序来说微信就是第三方授权;

(4)

@Configuration
@EnableAuthorizationServer  //放在过滤器的链条
public class QqAuth2ServerConfig extends
        AuthorizationServerConfigurerAdapter {
    
    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
        System.out.println("checkTokenAccess(\"permitAll()\")");
        oauthServer.tokenKeyAccess("permitAll()")  // /oauth/token
                .checkTokenAccess("permitAll()") // /ouath/check_token
                .allowFormAuthenticationForClients();
    }

}

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值