Spring Security OAuth2 Demo - Implicit authorization mode (the Implicit)

This article can be reproduced, but please indicate the source https://www.cnblogs.com/hellxz/p/oauth2_impilit_pattern.html

EDITORIAL

In the article OAuth 2.0 authorization concept and process of combing , we talked about OAuth 2.0 concepts and processes, the article Spring Security OAuth2 Demo - an authorization code pattern simple demonstration of the process OAuth2 authorization code mode, the paper continued to organize the implicit licensing model related information

Not easy to write the text, if wrong, please indicate in the comments area, thank you

This paper target

The use of relatively simple code demonstrates the implicit licensing model of the process, let the process more clear and understandable

The implicit licensing model review process

The implicit licensing model requires: User login and authorize third-party applications, direct access token is returned, by token access to resources

Compared authorization code mode, it is less an authorization code issued by the client in exchange for token using the authorization code process

The implicit licensing model applies scene

Application scenario has the following conditions:

  • User engagement: using implicit authorization requires interaction with the user , user login and authorization server for authorization
  • Single Page Application: SPA the front, no back-end or back-end part of an authorized party
  • Client Password: Access authorization is not required with third-party applications secret, provided that the resource service verification token use of client information and client (third-party applications) different and equipped with secret
  • Front: you must have a front-end , or can not use authorization capabilities
  • Client backend: Options, only if the application does not separate the front and rear end MVC scene
  • Resources belong party: authorized party

Demo structure

Mainly two roles, authorization server and resource server module two, the other as with several other demo, included in a parent project documentation

本文以及后续文章的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

Guess you like

Origin www.cnblogs.com/hellxz/p/oauth2_impilit_pattern.html