springsecurity 集成 oauth2

什么是oAuth2

简单来说,就是让一个系统可以直接访问另一个系统,通过授权码。

与单点登录的区别

什么是单点登录: 用户成功登录A系统,需要访问B系统时,可以不用输入用户名密码进行认证就可以直接访问B系统的资源。

什么是oauth2: A系统征求用户的同意后直接访问B系统,用户不需要登录也不需要访问B系统。

四种授权模式

1)授权码模式(oauth2 中最安全最完善的一种模式,应用场景最广泛)
A系统要访问B系统的资源,A系统询问用户是否同意其访问B系统的资源。如果用户同意,则B系统生成授权码给A,A系统带着授权码向B系统发送请求,并获取到令牌 token 和更新令牌 refresh token。(前提:用户有访问B系统的权限)

2)简化模式
跟授权码模式类似,去掉了授权码。直接获得B系统给的 token ,通过 token 访问B系统

3)密码模式
用户直接把自己访问B系统的账号密码告诉 A系统,A系统拿着用户的密码去访问B系统。

4)客户端模式
A系统直接脱离用户,以自己的身份去B系统获取 token,可以说完全是 AB 系统内部的交互,与用户无关了。该模式不太属于 oauth2 范畴

OAuth2表结构

oAuth2 自带有 7 张表

1)获取表结构地址: https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql

注意:这里的 sql 默认是 HSQLDB 的,我们用 mysql 的可以把 LONGVARBINARY 数据类型改成 BLOB
oauth_client_details 是核心表,后面测试时只要看这张表即可

表结构字段说明可参考博客 https://blog.csdn.net/qq_34997906/article/details/89609297

在这里插入图片描述

创建父工程

本文只贴 配置类代码,其他具体代码跟上一篇博客类似,具体可查看文末源码

注意 spring cloud 的版本匹配,本例用的 springboot2.3,可参考 https://start.spring.io/actuator/info
在这里插入图片描述

创建认证模块

即 B 系统的 oauth2 认证模块,B系统需要检测用户是否登录,用户成功登录了B系统才能授权给A系统去访问

@Configuration
@EnableWebSecurity
public class SpringsecurityConfig extends WebSecurityConfigurerAdapter {
    
    
    @Autowired
    private SysUserService userService;

    //配置加密
    @Bean
    public PasswordEncoder passwordEncoder() {
    
    
        return new BCryptPasswordEncoder(); //spring security 内置加密算法
    }

    //认证用户的来源
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
    
    
        auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
    }

    //Spring Security配置
    public void configure(HttpSecurity hs) throws Exception {
    
    
        hs.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginProcessingUrl("/login")
                .permitAll()
                .and()
                .csrf()
                .disable();
    }

    // 对象在oauth2认证服务中要使用,注意方法名不要乱改
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
    
    
        return super.authenticationManagerBean();
    }
}
@Configuration
@EnableAuthorizationServer
public class oauthServerConfig extends AuthorizationServerConfigurerAdapter {
    
    
    //数据库对象
    @Autowired
    private DataSource dataSource;

    //认证业务对象
    @Autowired
    private SysUserService userService;

    //授权模式专用对象
    @Autowired
    private AuthenticationManager authenticationManager;

    //客户端信息来源
    @Bean
    public JdbcClientDetailsService jdbcClientDetailsService() {
    
    
        return new JdbcClientDetailsService(dataSource);
    }

    //token保存策略
    @Bean
    public TokenStore tokenStore() {
    
    
        return new JdbcTokenStore(dataSource);
    }

    //授权信息保存策略
    @Bean
    public ApprovalStore approvalStore() {
    
    
        return new JdbcApprovalStore(dataSource);
    }

    //授权码模式数据来源
    @Bean
    public AuthorizationCodeServices authorizationCodeServices() {
    
    
        return new JdbcAuthorizationCodeServices(dataSource);
    }

    //指定客户端信息的数据来源
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    
    
        clients.withClientDetails(jdbcClientDetailsService());
    }

    //验证token的策略
    public void configure(AuthorizationServerSecurityConfigurer securityConfigurer) {
    
    
        securityConfigurer.allowFormAuthenticationForClients();
        securityConfigurer.checkTokenAccess("isAuthenticated()");
    }

    //oauth2的主配置
    public void configure(AuthorizationServerEndpointsConfigurer endpointsConfigurer) {
    
    
        endpointsConfigurer.approvalStore(approvalStore())
                .authenticationManager(authenticationManager)
                .authorizationCodeServices(authorizationCodeServices())
                .tokenStore(tokenStore());
    }

}

创建资源模块

即 B 系统的资源服务

@Configuration
@EnableResourceServer
public class OauthConfig extends ResourceServerConfigurerAdapter {
    
    

    @Autowired
    private DataSource dataSource;

    /**
     * 指定Token的持久化策略
     * InMemoryTokenStore 表示将 token 存储在内存
     * Redis 表示将 token 存储在Redis
     * JdbcTokenStore 表示将 token 存储在数据库
     * @return
     */
    @Bean
    public TokenStore jdbcTokenStore() {
    
    
        return new JdbcTokenStore(dataSource);
    }

    /**
     * 指定当前资源的id和存储方案
     * @param resource
     * @throws Exception
     */
    public void configure(ResourceServerSecurityConfigurer resource) throws Exception {
    
    
        resource.resourceId("source_api").tokenStore(jdbcTokenStore());
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
    
    
        http.authorizeRequests()
                //指定不同请求方式访问资源所需的权限
            .antMatchers(HttpMethod.GET, "/**").access("#oauth2.hasScope('read')")
            .antMatchers(HttpMethod.POST, "/**").access("#oauth2.hasScope('write')")
            .antMatchers(HttpMethod.PATCH, "/**").access("#oauth2.hasScope('write')")
            .antMatchers(HttpMethod.PUT, "/**").access("#oauth2.hasScope('write')")
            .antMatchers(HttpMethod.DELETE, "/**").access("#oauth2.hasScope('write')")
                .and()
            .headers().addHeaderWriter((request, response) -> {
    
    
            response.addHeader("Access-Control-Allow_Origin", "*");//允许跨域
            //如果是跨域的预检请求,则原封不动向下传达请求头信息
            if(request.getMethod().equals("OPTIONS")) {
    
    
                response.setHeader("Access-Control-Allow-Methods", request.getHeader("Access-Control-Allow-Methods"));
                response.setHeader("Access-Control-Allow-Headers", request.getHeader("Access-Control-Allow-Headers"));
            }

        });
    }
}

测试

1)添加测试数据(A系统在B系统注册的客户端信息)
B系统需要保存A系统的id,A系统可以访问哪些资源,都有什么权限,访问的模式,回调地址,是否需要用户同意
在这里插入图片描述

2)启动两个模块
注意请求路径的写法,是oauth2提供的,我们只需改变参数

  • 首先在网页上访问:http://localhost:8081/oauth/authorize?response_type=code&client_id=client01
    去获取授权码,这里需要用户输入账号密码登录
    在这里插入图片描述

  • 打开 postman 访问:http://localhost:8081/oauth/token,在 body 中加入如下参数
    grant_type
    client_id
    client_secret
    code
    username
    password
    在这里插入图片描述

本项目 GitHub 地址:https://github.com/godXiaogf/springsecurity_oauth2

猜你喜欢

转载自blog.csdn.net/Alias_fa/article/details/106973677