Revisit Oath2 Configuration of 0

Posted by edawg on Tue, 25 Jan 2022 12:13:41 +0100

preparation

Firstly, the UserDetailsService interface needs to be implemented to complete the loading of users; Note that the password here needs to be encrypted. If the database is plaintext, it needs to be encrypted and set later

Furthermore, a UserDetails interface needs to be implemented to complete the external output of user information;

In addition, it is necessary to implement a GrantedAuthority interface to complete the external output of user permissions;

Create an add / remove class for @ bean to return PasswordEncode. It is recommended to use the ready-made BCryptPasswordEncoder, or you can implement the PasswordEncoder interface and customize the encryption algorithm yourself

Create a class that inherits WebSecurityConfigurerAdapter
Override his configure (HttpSecurity http) method for Security related configuration

@Configuration
@EnableWebSecurity // Start WebSecurity [can be written in the configuration class]
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
       http.csrf().disable()  // Temporarily closed for testing
        .authorizeRequests()
               .antMatchers("/oauth/**","/login/**","/logout/**")  // Create matching rule
        .permitAll() // Release the matching rules described above
        .anyRequest().authenticated() // To switch to any request, the settings must be authenticated before they can be accessed
        .and().formLogin().permitAll(); // And release the form certification
    }
}

Different configurations are made for resources and authentication servers

Authorization server configuration

Create a class to inherit the AuthorizationServerConfigurerAdapter and override the configure(ClientDetailsServiceConfigurer clients) method
Configure the authorization server to load the authorization information of cooperative merchants, resource permission, authorization method and callback address

/**
 * Authorization server configuration
 * @author Guochao
 */
@Configuration
@EnableAuthorizationServer // Enable authorization server
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private PasswordEncoder passwordEncoder;
    // Configure client
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // Load partner app information
        // TODO formal environment uses this. Now it is convenient to test and use memory based configuration clients JDBC (), account and password data can also be checked in the database
        clients.inMemory()
                .withClient("pzh") // clientId, client id
                .secret(passwordEncoder.encode("123456"))  // The client password can be encrypted
                // The redirected address. After the user agrees to authorize, he will carry the authorization code and request the callback address to obtain the authorization code
                .redirectUris("https://www.baodu.com")  
                .scopes("all","userinfo","resource")  // Allowable scope of authorization
        .authorizedGrantTypes("authorization_code") // Authorization type. Select the authorization code mode here
        .autoApprove("all","userinfo") // Automatic authorization 
        // After automatic authorization is set, you can request permissions within the authorization and directly complete the authorization. Those outside the authorization will still jump to the user consent interface,
        // If you do not set the scope, or if you enter multiple scopes, one of them does not contain automatic authorization, all optional scopes will appear
        // . autoApprove(true) / / absolute automatic authorization. There is no need to write specific scopes that allow automatic authorization. All scopes allow automatic authorization
    }
}

Resource server configuration

@Configuration
@EnableResourceServer  // Enable resource services
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // Configure resource information with resource domain restrictions
                .antMatchers("/userinfo/**").access("#oauth2.hasAnyScope('userinfo','all')")
                .and()
                // Matching resources: match the addresses of the above resources. The resources configured in them will be protected and can only be accessed after all authentication
                .requestMatchers().antMatchers("/resource/**")
                                    // The access rights of this resource are configured above. Protection still needs to be configured here
                                  .antMatchers("/userinfo/**")
                .and()
                // Specify any request, and set r any request to be accessed after authorization
                .authorizeRequests().anyRequest().authenticated()
                .and().csrf();
    }
}

Next, we will test the authorization code mode:

The first is to obtain the authorization code

Partner client id=pzh,
Callback address = www.baidu.com com
Response mode = code
Resource field = all
Obtain authorization code
http://localhost:9999/oauth/authorize?response_type=code&client_id=pzh&redirect_uri=https://www.baidu.com&scope=all
Space each scope authorization when requesting multiple authorizations
http://localhost:9999/oauth/authorize?response_type=code&client_id=pzh&redirect_uri=https://www.baidu.com&scope=all userinfo&state=iuza79Mlap
After testing, it is found that it can simplify:
http://localhost:12301/oauth/authorize?response_type=code&client_id=pzh In this way, if scpe is not specified, all allowed scop es will be listed for users to choose, and the options depend on the merchant's registration information

After the user agrees, it will be redirected to the callback address set by the merchant, and the code authorization code will be attached. If we add the state parameter at the same time, the authorization code will also be returned when we return it. You can use state as consistency verification to prevent scrf attacks

Exchange authorization code for access_token

All information must be consistent with that filled in by the registered merchant
Code = authorization code
grant_type = authentication mode
redirect_uri = callback address
client_id = client id,
At the same time, you need to use the client id and password, and use the basic auth mode to log in
After logging in, you can get the access token

{
    "access_token": "8d1a8b93-f963-4f5c-8cc1-267f099cbbd1",
    "token_type": "bearer",
    "expires_in": 42645,
    "scope": "all"
}

Using access_token reads user resources

http://localhost:9999/oauth/token?code=7BxIn2&grant_type=authorization_code&redirect_uri=https://www.baidu.com&scope=all&client_id=pzh

Sample

Basic dependence

   <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.5.RELEASE</version>
    </parent>

    <properties>
        <spring.cloud-version>Hoxton.SR8</spring.cloud-version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <!--System-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.3.3.RELEASE</version>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>


        <!--Tool-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.8.1</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.75</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-core</artifactId>
            <version>5.7.9</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>
    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.3.RELEASE</version>
            </plugin>
        </plugins>
    </build>

UserDetails example

// The class used to extract user information from the framework is responsible for providing the framework with basic attribute acquisition methods;
@Data
public class UserDetail implements UserDetails {


    private String password;
    private String username;
    private List<GrantedAuthority> auth;


    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
       return this.auth;
    }

    @Override
    public String getPassword() {
        return this.password;
    }

    @Override
    public String getUsername() {
        return this.username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    public UserDetail() {
    }

    public UserDetail(String password, String username, List<GrantedAuthority> auth) {
        this.password = password;
        this.username = username;
        this.auth = auth;
    }
    // Provides a string conversion array method for easy calling
    public UserDetail(String password, String username, String auth) {
        this.password = password;
        this.username = username;
        List<String> strAuths = Arrays.asList(auth.split(","));
        this.auth=strAuths.size()==0?new ArrayList<>():strAuths.stream().map(MyGrantedAuthority::new).collect(Collectors.toList());
    }
}

loadUsername sample

/**
 * User loading
 */
@Service
public class UserLoad implements UserDetailsService {
    @Autowired
    private UserService userService;
    @Autowired
    private PasswordEncoder passwordEncoder;

    // Load user, password encryption
    @Override
    public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
        User user = userService.getUser(name);
        return new UserDetail(passwordEncoder.encode(user.getPwd()), user.getName(), user.getAuth());
    }
}

security configuration example of others

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
​
    @Override
    protected void configure(HttpSecurity http) throws Exception {
            //authorizeRequests indicates the permission required to start the description
            http.httpBasic()
                    .and()
                .formLogin().loginPage("/login.html")
                .defaultSuccessUrl("/admin/index.html")
                .loginProcessingUrl("/login").failureUrl("/error.html")
                    .and()
                .logout().logoutSuccessUrl("/login.html")
                    .and()
                .authorizeRequests()
                .antMatchers("/login.html").permitAll()
                .antMatchers("/error.html").permitAll()
                .antMatchers("/css/**").permitAll()
                .antMatchers("/js/**").permitAll()
                .antMatchers("/img/**").permitAll()
                .antMatchers("/plugins/**").permitAll()
                    .and()
                .authorizeRequests()
                .antMatchers("/**").hasRole("USER")
                .anyRequest().authenticated()
                .and().csrf().disable();
        
        http.headers().frameOptions().sameOrigin();
    }
​
}

Other people's authentication server configuration

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // Configure client
        clients
                // Use memory settings
                .inMemory()
                // client_id
                .withClient("client")
                // client_secret
                .secret(passwordEncoder.encode("secret"))
                // Authorization type: authorization code, refresh token, password, client, simplified mode, SMS verification code "refresh_token"
                .authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "sms_code")
                // The authorization scope can also be used for authentication according to the scope ID
                .scopes("admin:org","write:org","read:org")
                .accessTokenValiditySeconds(300)
                .refreshTokenValiditySeconds(3000)
                // Whether the authorization page of authorization code mode is authorized automatically
                //.autoApprove(false)
                // Permissions owned
                .authorities("add:user")
                // Resource service ID allowed to access
                //.resourceIds("oauth2-resource-server001-demo")
                // Register callback address
                .redirectUris("http://localhost:20000/code");
    }
https://blog.csdn.net/qq_43437874/article/details/121552989

Topics: Operation & Maintenance server Spring Security security