springsecurity整合oauth2

什么是oauth?

oauth协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是oauth的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此oauth是安全的。
举个栗子:比如说我进入了一个网页,这个网页提示我要登陆,但是我不想在这个网站再注册一个账号,刚好提供了微信登陆,支付宝登陆。这两款软件是我们使用很广泛的软件,大家应该都有的,然后我点微信登陆,弹出一个二维码,提示我扫码,授权给这个网站就登陆成功了。

手写一个类似微信给第三方授权的demo
maven
<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
    </parent>
        <dependencies>
            <!-- SpringBoot整合Web组件 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </dependency>

            <!-- springboot整合freemarker -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-freemarker</artifactId>
            </dependency>
            <!-->spring-boot 整合security -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
            <!-- Spring Security OAuth2 -->
            <dependency>
                <groupId>org.springframework.security.oauth</groupId>
                <artifactId>spring-security-oauth2</artifactId>
                <version>2.2.1.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt</artifactId>
                <version>0.6.0</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.62</version>
            </dependency>
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
            </dependency>
        </dependencies>
oauth配置
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
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.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.stereotype.Component;

/**
 * 认证授权Server端
 */
@Component
@EnableAuthorizationServer
public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        //允许表单提交
        security.allowFormAuthenticationForClients()
                .checkTokenAccess("permitAll()");
    }

    /**
     * appid mayikt secret= 123456
     *
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                //client_id
                .withClient("mykt")
                // 第二次登陆
                .secret(passwordEncoder.encode("123456"))
                // 授权码
                .authorizedGrantTypes("authorization_code")
                // 作用域
                .scopes("all")
                // 资源的id
                .resourceIds("mayikt_resource")
                // 回调地址
                .redirectUris("http://www.mayikt.com/callback");
    }
}
PasswordEncoder Bean配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class PasswordEncoderConfig {
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

启动项目,浏览器中输入

//这里的client_id参数是oauth里面client_id配置的那个
http://localhost:8080/oauth/authorize?client_id=mykt&response_type=code

请求的这个地址是oauth封装好的接口,这个就好比如一些网站点微信登陆弹出来的二维码,他这个二维码就是由这个地址转换的。
在这里插入图片描述
这里就出现这种情况,后面我查了一下,说是高版本oauth要配合security使用,那么我们就一起把security整合起来

security配置,这个时候我们要将PasswordEncoder Bean配置移到这里
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;


@Component
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 需要填写 认证账户  mykt
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
        .withUser("mykt")
        .password(passwordEncoder().encode("mykt"))
        .authorities("/*");

    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated() //所有请求都需要通过认证
                .and()
                .formLogin() //form表单验证
                .and()
                .csrf().disable(); //关跨域保护
    }
}

登陆账号密码已经卸载security配置中(如果想动态从数据获取,欢迎大家看我领一篇spring-security详解
在这里插入图片描述
登陆进去
在这里插入图片描述
这个就和微信授权页面一样,我们点同意,选第一个
在这里插入图片描述
现在呢出现404,我没有这个接口,这个不重要,重要的是url中code的值。

http://www.mayikt.com/callback?code=5ZJ07r

然后我们将code值填入到这个地址中code属性中,redirect_uri回调地址,scope是所有权限,这个地址获取到token

http://localhost:8080/oauth/token?code=5ZJ07r&grant_type=authorization_code&redirect_uri=http://www.mayikt.com/callback&scope=all

将这个地址在浏览器中打开
在这里插入图片描述
注意: 这个地方呢不上我们上次输入的账号密码了是oauth里面的
在这里插入图片描述
输入正确的账号密码之后,出现这种情况
在这里插入图片描述
什么意思呢?就是这个接口不是get类型,是post,把地址复制出来,那么我们用postman看看。
在这里插入图片描述

这里获取到的token就好比如拿到接口服务的通行证,那么我们接口模拟服务端,新创建一个服务8001
资源配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;

/**
 * 资源配置类
 */
@Configuration
@EnableResourceServer
public class ResourcesConfig extends ResourceServerConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Primary
    @Bean
    public RemoteTokenServices remoteTokenServices(){
        RemoteTokenServices tokenServices =new RemoteTokenServices();
        //验证token地址
        tokenServices.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token");
        tokenServices.setClientId("mykt");
        tokenServices.setClientSecret("123456");
        return  tokenServices;
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        //设置创建session策略
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
        //@formatter:off
        //所有请求必须授权
        http.authorizeRequests()
                .anyRequest().authenticated();
        //@formatter:on
    }

    public void configure(ResourceServerSecurityConfigurer resource){
        //资源id唯一
        resource.resourceId("mykt_resource").stateless(true);
    }

}
模拟
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MemberController {
    @GetMapping("/getMember")
    public String getMember() {
        return "我是会员服务接口";
    }
}
可以看到getMember接口很简单的一个接口,那我们最简单的方式就是:http://localhost:8081/getMember 是不是就可以获取到数据了,nonono!之前你是不是获取到鉴权的token,那么这个token就是你现在访问的通信证,没有通信证就无法访问,那么这么做有什么好处?可以验证用户信息,只对认证的用户才能调用。那么微信网页第三方登陆是不是一个道理。
没有传token,就返回没有这个资源

在这里插入图片描述

然后按照上面的操作拿到token再传进去,就可以正常访问

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值