springSecurity oAuth2

oAuth2:是一种认证与授权的标准。
springSecurity:是一种提供oAuth2的安全框架加。

为什么需要oAuth2?

我们假设你有一个“云笔记”产品,并提供了“云笔记服务”和“云相册服务”,此时用户需要在不同的设备(PC、Android、iPhone、TV、Watch)上去访问这些“资源”(笔记,图片)

那么用户如何才能访问属于自己的那部分资源呢?此时传统的做法就是提供自己的账号和密码给我们的“云笔记”,登录成功后就可以获取资源了。但这样的做法会有以下几个问题:

“云笔记服务”和“云相册服务”会分别部署,难道我们要分别登录吗?
如果有第三方应用程序想要接入我们的“云笔记”,难道需要用户提供账号和密码给第三方应用程序,让他记录后再访问我们的资源吗?
用户如何限制第三方应用程序在我们“云笔记”的授权范围和使用期限?难道把所有资料都永久暴露给它吗?
如果用户修改了密码收回了权限,那么所有第三方应用程序会全部失效。
只要有一个接入的第三方应用程序遭到破解,那么用户的密码就会泄露,后果不堪设想。 为了解决如上问题,oAuth 应用而生。

oAuth2的常见名词解释:
第三方程序(Third-party application):又称客户端(client),我们会在这些设备中安装我们自己研发的 APP。又比如我们的产品想要使用 QQ、微信等第三方登录。对我们的产品来说,QQ、微信登录是第三方登录系统。我们又需要第三方登录系统的资(头像、昵称等)。对于 QQ、微信等系统我们又是第三方应用程序。
HTTP 服务提供商(HTTP service): 我们的云笔记产品以及 QQ、微信等都可以称之为“服务提供商”。
资源所有者(Resource Owner): 又称之为用户(user)。
用户代理(User Agent): 比如浏览器,代替用户去访问这些资源。
认证服务器(Authorization server): 即服务提供商专门用来处理认证的服务器,简单点说就是登录功能(验证用户的账号密码是否正确以及分配相应的权限)
资源服务器(Resource server): 即服务提供商存放用户生成的资源的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。简单点说就是资源的访问入口,比如上节中提到的“云笔记服务”和“云相册服务”都可以称之为资源服务器。

交互过程:

在这里插入图片描述

创建认证服务器:

认证服务器:主要用于验证客户端身份和用户的省份等信息,若正确则发放授权码,通过授权码去拉取token,认证服务器有token后,可以去资源服务器获取资源。

  1. 导入securityoAuth2的依赖
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-oauth2</artifactId>
        <version>2.1.4.RELEASE</version>
    </dependency>
  1. 配置AuthorizationServerConfiguration类,该类继承AuthorizationServerConfigurerAdapter类,作用是配置用户信息(基于JDBC连接或者基于内存存储),例基于JDBC连接代码如下
package com.gssl.oAuth2.server.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;

import javax.sql.DataSource;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        // 配置数据源(注意,我使用的是 HikariCP 连接池),以上注解是指定数据源,否则会有冲突
        return DataSourceBuilder.create().build();
    }

    /**
     * 配置以JDBC的方式存储token数据
     * @return
     */
    @Bean
    public TokenStore tokenStore(){
        return new JdbcTokenStore(dataSource());
    }
    /**
     * 配置一JDBC的方式存储clientDetailsService数据
     * @return
     */
    @Bean
    public ClientDetailsService jdbcClientDetails (){
        return new JdbcClientDetailsService(dataSource());
    }

    @Autowired
     BCryptPasswordEncoder passwordEncoder;

    /**
     * 配置客服端保存的方式
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 配置客户端以JDBC的方式保存信息
        clients.withClientDetails(jdbcClientDetails());
    }

    /**
     * 配置令牌保存的方式
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore());
    }
}


配置服务器完全相关配置(对用户信息的配置)

package com.gssl.oAuth2.server.config;

import com.gssl.oAuth2.server.config.service.UserDetailsServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Bean
    @Override
    public UserDetailsService userDetailsService() {
        return new UserDetailsServiceImpl();
    }
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService());
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/oauth/check_token");
    }
}

  1. application.yml
spring:
  application:
    name: oAuth2-server
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    jdbc-url: jdbc:mysql://127.0.0.1:3306/oAuth2?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root
    hikari:
      minimum-idle: 5
      idle-timeout: 600000
      maximum-pool-size: 10
      auto-commit: true
      pool-name: MyHikariCP
      max-lifetime: 1800000
      connection-timeout: 30000
      connection-test-query: SELECT 1
server:
  port: 8080
mybatis:
  type-aliases-package: com.gssl.oAuth2.server.domain
  mapper-locations: classpath:mapper/*.xml
  1. 查询封装用户信息
package com.gssl.oAuth2.server.config.service;

import com.gssl.oAuth2.server.domain.TbPermission;
import com.gssl.oAuth2.server.domain.TbUser;
import com.gssl.oAuth2.server.service.TbPermissionService;
import com.gssl.oAuth2.server.service.TbUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;


import java.util.ArrayList;
import java.util.List;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private TbUserService tbUserService;

    @Autowired
    private TbPermissionService tbPermissionService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        TbUser tbUser = (TbUser) tbUserService.getByusername(username);
        //GrantedAuthority权限、角色,User()方法中需要传入权限角色的集合作为参数即 List<GrantedAuthority>
        List<GrantedAuthority> grantedAuthorities= new ArrayList<>();
        if(tbUser!=null){
            List<TbPermission> tbPermissions = tbPermissionService.selectByUserId(tbUser.getId());
            for (TbPermission o:tbPermissions
                 ) {
                grantedAuthorities.add(new SimpleGrantedAuthority(o.getEnname()));
            }

        }
        return new User(tbUser.getUsername(),tbUser.getPassword(),grantedAuthorities);
    }
}

创建资源服务器

该部分实际上是对要资源的权限控制,自己配置资源的访问权限,通过认证服务器的token来认证服务器比较该用户是否有访问的权限

  1. 配置所需保护的资源路径及权限,需要与认证服务器配置的授权部分对应,建立ResourceServer
    Configuration类继承ResourceServerConfigurationAdapter类重写configure(HttpSecurity http) 方法。
package com.gssl.oAuth2.resource.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .exceptionHandling()
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                // 以下为配置所需保护的资源路径及权限,需要与认证服务器配置的授权部分对应,应当从数据库中读出来
                .antMatchers("/").hasAuthority("SystemContent")
                .antMatchers("/view/**").hasAuthority("SystemContentView")
                .antMatchers("/insert/**").hasAuthority("SystemContentInsert")
                .antMatchers("/update/**").hasAuthority("SystemContentUpdate")
                .antMatchers("/delete/**").hasAuthority("SystemContentDelete");
    }

}

操作流程
在这里插入图片描述

  • 初始化资源服务器数据库
  • POM 所需依赖同认证服务器
  • 配置资源服务器
  • 配置资源(Controller)
  • 初始化资源服务

验证方式

1.请求认证服务器获取授权码

http://localhost:8080/oauth/authorize?client_id=client&response_type=code
var foo = 'bar';

2.登录认证
在这里插入图片描述
在这里插入图片描述
3.认证完成后通过服务器发放的code

//该地址为在oauth_client_details表中填写的回调地址
http://www.funtl.com/?code=1JuO6V
var foo = 'bar';

4.通过code去拉取token,通过 CURL 或是 Postman 请求
在这里插入图片描述

4.通过access_token去资源服务器拉取资源.
该文章转至https://funtl.com/zh/spring-security-oauth2/%E5%88%9B%E5%BB%BA%E8%B5%84%E6%BA%90%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%A8%A1%E5%9D%97.html#%E8%AE%BF%E9%97%AE%E8%B5%84%E6%BA%90,仅供自己总结复习。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值