봄 보안 OAuth2를 데모 - 암시 인증 모드 (암시)

이 문서는 재현 할 수 있지만 소스를 표시하시기 바랍니다가 https://www.cnblogs.com/hellxz/p/oauth2_impilit_pattern.html

사설

문서에서 의 OAuth 2.0 인증 개념 및 빗질의 과정 , 우리의 OAuth에 대해 2.0 개념과 과정, 기사 이야기 봄 보안 OAuth2를 데모 - 인증 코드 패턴 공정으로 OAuth2 인증 코드 모드의 간단한 데모를 용지는 암시 라이센스 모델을 구성하기 위해 계속 관련 내용

잘못 코멘트 영역에 표시하시기 바랍니다 경우, 텍스트를 쉽게 작성할 수 없음, 감사합니다

이 논문 대상

비교적 간단한 코드를 사용하자, 프로세스의 암시 라이센스 모델을 설명하는 과정보다 명확하고 이해하기

암시 라이센스 모델 검토 프로세스

암시 라이센스 모델이 필요합니다 자원에 대한 토큰에 액세스하여 사용자 로그인 및 권한 부여 타사 응용 프로그램, 반환되는 토큰 직접 액세스,

비교 인증 코드 모드, 그것은 인증 코드 프로세스를 사용하여 토큰 교환의 클라이언트가 발행 한 적은 인증 코드입니다

암시 라이센스 모델은 현장 적용

응용 프로그램 시나리오는 다음과 같은 조건이 있습니다 :

  • 사용자 참여 : 암시 적 권한을 사용이 필요 사용자와의 상호 작용을 허가, 사용자 로그인 및 권한 부여 서버를
  • 단일 페이지 응용 프로그램 : SPA 전면, 인증 된 당사자의 어떠한 백 - 엔드 또는 백 엔드 부분도
  • 클라이언트 암호 : 액세스 권한이 필요하지 않습니다 자원 클라이언트 정보와 클라이언트 (타사 응용 프로그램) 다른의 토큰 사용 검증 서비스 및 비밀 장착 된 것을 제공, 타사 응용 프로그램 암호를 사용하여
  • 전면 : 당신은 프런트 엔드가 있어야합니다 , 또는 인증 기능을 사용할 수 없습니다
  • 클라이언트 백엔드 : 옵션, 응용 프로그램은 전면 및 후면 끝 MVC 장면을 분리하지 않는 경우에만
  • 권한을 부여받은 자 : 자 속하는 자료

데모 구조

주로 부모 프로젝트 문서에 포함 된 두 가지 역할, 권한 부여 서버와 리소스 서버 모듈이, 여러 가지 다른 데모와 같은 다른,

本文以及后续文章的demo均放在GitHub上,欢迎大家Star & Fork,源码地址:https://github.com/hellxz/spring-security-oauth2-learn

Maven依赖

        <!--Spring Security-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!--Spring Boot Starter Web 所有demo均使用web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Spring Security OAuth2 -->
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>${spring-security-oauth2.version}</version>
        </dependency>

搭建授权服务器

项目启动类不多说,直接贴代码,讲讲主要内容

先说下SecurityConfig

package com.github.hellxz.oauth2.config;

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.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 java.util.Collections;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

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

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // @formatter: off
        auth.inMemoryAuthentication()
                .withUser("hellxz")
                .password(passwordEncoder().encode("xyz"))
                .authorities(Collections.emptyList());
        // @formatter: on
    }

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

参考了上文的话,这里基本上没有什么变化,除了开启web安全外,重写了认证管理器的用户提供部分、简单配置了所有资源都需要认证

授权服务主要配置AuthorizationConfig

package com.github.hellxz.oauth2.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
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;

//授权服务器配置
@Configuration
@EnableAuthorizationServer //开启授权服务
public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        //允许表单提交
        security.allowFormAuthenticationForClients()
                .checkTokenAccess("permitAll()"); //参数与security访问控制一致
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // @formatter: off
        clients.inMemory()
                .withClient("client-a") //client端唯一标识
                    .authorizedGrantTypes("implicit") //授权模式标识
                    .accessTokenValiditySeconds(120) //访问令牌的有效期,这里设置120s
                    .scopes("read_user_info") //作用域
                    .resourceIds("resource1") //资源id
                    .redirectUris("http://localhost:9001/callback") //回调地址
                    .and()
                .withClient("resource-server") //资源服务器校验token时用的客户端信息,仅需要client_id与密码
                    .secret(passwordEncoder.encode("test"));
        // @formatter: on
    }
}

因为最复杂的授权码已经有讲过了,这里简单说下,授权配置除了开启授权服务器,并重写认证服务器安全配置(接收客户端提交请求部分)允许客户端进行表单提交;另外配置了一个客户端的信息,包含其标识id、授权模式标识、令牌有效期、回调地址这几个必要的配置;

为了更清晰地区分第三方应用的客户端与资源服务器的客户端,这里额外配置了资源服务的客户端信息

测试授权服务器

  • 获取token

浏览器访问地址:http://localhost:8080/oauth/authorize?client_id=client-a&redirect_uri=http://localhost:9001/callback&response_type=token&scope=read_user_info

请求参数列表:

  • client_id=客户端id
  • redirect_uri=回调url 一定要与授权服务器配置保持一致,否则得不到授权码
  • response_type=token 简化模式必须是token
  • scope=作用域 与授权服务器配置保持一致
  • state=自定义串(可选)

返回响应会回调我们之前输入的回调地址,包含access_token和token类型及过期时间

搭建资源服务器

资源服务器也不复杂,一个资源服务器配置类,一个controller、一个vo,还有启动类(这里就不贴了,详见源码)

ResourceController主要接收用户传来的用户名,返回一个json串,这里用标准错误输出高亮了下登录用户信息

package com.github.hellxz.oauth2.web.controller;

import com.github.hellxz.oauth2.web.vo.UserVO;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ResourceController {

    @GetMapping("/user/{username}")
    public UserVO user(@PathVariable String username){
        System.err.println(SecurityContextHolder.getContext().getAuthentication());
        return new UserVO(username, username + "@foxmail.com");
    }
}

UserVO

package com.github.hellxz.oauth2.web.vo;

public class UserVO {
    private String username;
    private String email;

    public UserVO(String username, String email) {
        this.username = username;
        this.email = email;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

资源服务器配置类ResourceConfig

package com.github.hellxz.oauth2.config;

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 ResourceConfig extends ResourceServerConfigurerAdapter {

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

    @Primary
    @Bean
    public RemoteTokenServices remoteTokenServices() {
        final RemoteTokenServices tokenServices = new RemoteTokenServices();
        tokenServices.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token");
        //这里的clientId和secret对应资源服务器信息,授权服务器处需要配置
        tokenServices.setClientId("resource-server");
        tokenServices.setClientSecret("test");
        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
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId("resource1").stateless(true);
    }
}

资源服务器相对授权服务器更简单,仅需要开启EnableResourceServer,实现HttpSecurity配置、ResourceServerSecurityConfigurer配置 和 校验token的配置,这里使用远程调用授权服务器的做法;

需要注意的是区分资源服务器client信息和第三方应用客户端信息,之前这里有些模糊,直到著此文时方才发现这两者应区分(隐式授权可以不用密码啊,如果第三方应用等于资源服务器client,在不设置client_secret情况下,会校验失败,无法访问资源)

一般而言,校验token的配置如果是资源服务器自己校验,则需要在configure(ResourceServerSecurityConfigurer resources)这个方法中添加token存储(tokenStore)的位置等信息

使用token访问资源

结束

最近比较忙,抽时间整理代码时发现:我对OAuth2的资源服务器与授权服务器的client配置有些模糊,现在已经清晰多了,并且及时修改了demo。如果本文对你有帮助,欢迎点推荐,Github点Star :happy:

OAuth2系列demo仓库地址:https://github.com/hellxz/spring-security-oauth2-learn

纸上得来终觉浅,觉知此事要躬行。愿大家共勉

本文可以转载,但请注明出处https://www.cnblogs.com/hellxz/p/oauth2_impilit_pattern.html

추천

출처www.cnblogs.com/hellxz/p/oauth2_impilit_pattern.html