OAuth2.0及Spring实现

一、什么是OAuth2.0

引用百度的解释:

OAuth2.0是OAuth协议的延续版本,但不向前兼容OAuth 1.0(即完全废止了OAuth1.0)。OAuth 2.0关注客户端开发者的简易性。要么通过组织在资源拥有者和HTTP服务商之间的被批准的交互动作代表用户,要么允许第三方应用代表用户获得访问的权限。同时为Web应用,桌面应用和手机,和起居室设备提供专门的认证流程。2012年10月,OAuth 2.0协议正式发布为RFC 6749

百度百科

 

说简单点就是用来认证的。

 

二、什么场景下需要使用OAuth2.0

一般来说需要开放能力给第三方的时候需要用到认证,注意是第三方,内部系统一般来说不用,因为内部我们一般有自己的用户中心或者登录中心,这些系统可以用来做认证,而为什么开放给第三方需要认证呢,主要有以下几方面的原因:

1、安全

内部调用用户中心,邮箱、手机号等信息一般都可以拿到,而开放给第三方的时候我们需要做好安全处理,以防第三方的原因造成个人数据泄露等问题。

 

2、重用

如果每个系统开放出去都需要自己实现一套认证流程,那系统的交互效率太低,所以会有一套统一的认证过程,来和第三方交互,一般来说这些在网关上用的比较多。

 

有兴趣可以看下如何集成qq登录,它的实现就是遵循OAuth2.0标准。

 

三、OAuth2.0流程及概念介绍

 

在介绍流程之前,先举1个场景,假如有个社交网站www.xxx.com想集成qq登录,用户在社交网站注册后会存放其个人数据,通过 www.xx.com/personal可以访问用户的头像等信息(实际url可能是网关的),我们也忽略参数等细节。

 

1、OAuth2.0角色

大概有以下几类角色:

 

A、Client

有的也叫第三方应用程序,指想集成资源访问的应用。

说的有点绕,拿上面的例子来说www.xxx.com 指的就是Client。

 

B、Resource Owner

资源所有者,一般指用户;

因为我们需要访问用户的邮箱、手机号信息,这些是属于用户的,需要征得用户同意,所以用户是资源所有者。

 

C、User Agent

用户代理,指浏览器。

 

D、Authorization server

认证服务器,即服务提供商专门用来处理认证的服务器。

 

E、Resource server

资源服务器,即服务提供商存放用户生成的资源的服务器。

回到上面的例子,假如我们要访问用户邮箱,即通过 www.xxx.com/personal这个接口获取,那资源服务器就是www.xxx.com所在服务器。

 

在部署上它可以与认证服务器在同一台服务器,也可以在不同的服务器。

 

 

2、OAuth2.0几种模式

A、授权码模式(Authorization code Grant)

贴上官方的图

 

步骤如下:

(1)用户访问Client,即www.xxx.com,后者将前者导向认证服务器,即graph.qq.com/oauth2.0/show;

 

(B)用户选择是否给予客户端授权;

 

(C)假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个授权码。

 

(D)客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。

 

(E)认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)的请求。

 

B、简化模式(Implicit Grant)

 

 

同授权码模式相对,区别在于没有获取授权码的步骤。

 

C、密码模式(Resource Owner Password Credentials Grant)

 

 

(1)用户向客户端(www.xxx.com)提供用户名和密码。

(2)客户端(www.xxx.com)将用户名和密码发给认证服务器(open.qq.com),向后者请求令牌。

(3)认证服务器确认无误后,向客户端提供访问令牌。

 

D、客户端模式(client credentials)

 

这是一种最简单的模式,只要client请求,即在www.xxx.com后台任务发起请求,我们就将AccessToken发送给它。

 

 

 

四、Spring实现

因为篇幅的原因,不准备写太多代码,我们以一个小的demo来跑下流程。

 

在idea中创建一个springbot的项目,注意选择spring web和spring security,

 

新增认证服务器代码

@Configuration@EnableAuthorizationServerpublic class ConfigAdapter extends AuthorizationServerConfigurerAdapter {
    @Autowired    private AuthenticationManager authenticationManager;
    @Autowired    private DataSource myDataSource;
    @Override    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {        super.configure(security);    }
    @Bean    public TokenStore tokenStore() {        return new InMemoryTokenStore();    }
    @Bean    public PasswordEncoder passwordEncoder(){        return NoOpPasswordEncoder.getInstance();    }
    /**     * 数据源     * @return     */    public DataSource dataSource(){        return myDataSource;    }
    @Override    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {        clients.inMemory()                .withClient("client-id")                .secret("client-secret")                .scopes("read", "write")                .authorizedGrantTypes("password", "refresh_token", "code", "authorization_code")  //对应response_type是否有权限                .redirectUris("http://www.baidu.com")                .authorities("user:view");    }
    @Override    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {        endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager)                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);    }
}

 

再加入认证逻辑,这里先写死,简单点:

public class MyAuthenticationManager implements AuthenticationManager {
    /*        授权过程     */    public Authentication authenticate(Authentication authentication) throws AuthenticationException{        String userName, password;
        userName = (String)authentication.getPrincipal();        password = (String)authentication.getCredentials();
        if ((userName == "edward") && (password == "123")){            Authentication res = new UsernamePasswordAuthenticationToken(authentication.getPrincipal()                    , authentication.getPrincipal());            return res;        }
        return null;    }}

 

再配置用户信息,也是先写死:

@Configuration
@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter {    @Bean    MyAuthenticationProvider myAuthenticationProvider() {        return new MyAuthenticationProvider();    }
    @Override    protected void configure(AuthenticationManagerBuilder auth) throws Exception {        auth.inMemoryAuthentication()                .withUser("edward").password("123").authorities("USER")                .and()                .withUser("user_2").password("123456").authorities("USER");    }
    @Override    protected void configure(HttpSecurity http) throws Exception{        //http.regexMatcher("/image/.+").authorizeRequests().anyRequest().authenticated();        http.authorizeRequests().antMatchers("/post/**", "/oauth/**", "/login/**").permitAll()                .anyRequest().authenticated()                .and().formLogin().permitAll()        ;    }
    @Bean    @Override    public AuthenticationManager authenticationManagerBean() throws Exception {        AuthenticationManager manager = super.authenticationManagerBean();        return manager;    }
    @Bean    @Override    protected UserDetailsService userDetailsService(){        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();        manager.createUser(User.withUsername("edward").password("123").authorities("USER").build());        manager.createUser(User.withUsername("user_2").password("123456").authorities("USER").build());        return manager;    }
}

 

再新加一个控制器, 这个表示我们的要保护的资源

@RestController@RequestMapping("/user")public class UserController {
    @GetMapping("hello")    public String hello(){        return "hello user";    }}

 

然后在浏览器访问授权码模式的几个URL:

1、获取token

http://localhost:8080/oauth/authorize?response_type=code&client_id=client-id&redirect_uri=http://www.baidu.com

 

2、根据code获取token

http://localhost:8080/oauth/token?grant_type=authorization_code&code=Dx5tnU&client_id=client-id&client_secret=client-secret&redirect_uri=http://www.baidu.com

 

这一步会跳转到www.baidu.com,并且返回一个accessToken

 

3、根据accessToken访问资源

http://localhost:8080/user/hello?accessToken=123

 

中间需要登录,输入上面定义的账号和密码

edward

123

 

想持续获得最新的技术干货,请关注我的公众号吧

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值