java authentication and authorization (Spring Security)

Table of contents

1. Introduction to Spring Security

2. Getting started with authentication and authorization

2.2.1 Create authentication service project

1. Deploy the authentication service project

2. Configure the dependencies required by Spring Security

3. The initial project comes with a Controller class, as follows

4. Security configuration is required.

3. Authorization test

1. Configure what permissions the user has.

2. Specify the relationship between resources and permissions.

4. Working principle

The execution flow of Spring Security is as follows:


1. Introduction to Spring Security

        The authentication function is a function that almost every project must have, and it has nothing to do with business. There are many authentication frameworks on the market, such as: Apache Shiro, CAS, Spring Security, etc. Since this project is built based on Spring Cloud technology, and Spring Security is a member of the spring family and is well integrated with Spring Cloud, this project uses Spring Security as the technical framework for the authentication service.

Spring Security is a powerful and highly customizable authentication and access control framework that focuses on providing authentication and authorization for Java applications.

Project homepage: https://spring.io/projects/spring-security

Spring cloud Security: https://spring.io/projects/spring-cloud-security

2. Getting started with authentication and authorization

2.2.1 Create authentication service project

Below we use the Spring Security framework to quickly build an authentication and authorization functional system.

1. Deploy the authentication service project

Create a xuecheng-plus-auth project in your own project directory.

This project is an ordinary spring boot project that can connect to the database.

This project does not have the function of authentication and authorization.

2. Configure the dependencies required by Spring Security

<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>

3. The initial project comes with a Controller class, as follows

package com.xuecheng.auth.controller;

import com.xuecheng.ucenter.mapper.XcUserMapper;
import com.xuecheng.ucenter.model.po.XcUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Mr.Zhang
 * @version 1.0
 * @description 测试controller
 * @date 2023/3/16 10:25
 */
@Slf4j
@RestController
public class LoginController {

    @Autowired 
    XcUserMapper userMapper; 


    @RequestMapping("/login-success") 
    public String loginSuccess() { 

        return "Login successful"; 
    } 


    @RequestMapping("/user/{id}") 
    public ) 
    String 
        id 
    ) 
        { 
    _ 
        _ 
    _ 
    _ r2") 
    public String r2(){ 
        return "Access r2 resource"; 
    } 
}




4. Security configuration is required.

Building a WebSecurityConfig.java under config requires three parts:

1. User information

Configure two users in memory: zhangsan and lisi

The permissions owned by user zhangsan are p1

The permissions owned by the lisi user are p2

2. Password method

Temporarily use clear text mode

3. Security interception mechanism

Requests starting with /r/** require authentication

Log in successfully to the success page

code show as below:

package com.xuecheng.auth.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
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.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

/**
 * @author Mr.M
 * @version 1.0
 * @description 安全管理配置
 * @date 2023/3/16 10:25
 */
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 


    //Configure user information service 
    @Override
    @Bean
    public UserDetailsService userDetailsService() {
        //Configure user information here, temporarily use this method to store users in memory 
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); 
        manager.createUser(User.withUsername("zhangsan").password("123").authorities(" p1").build()); 
        manager.createUser(User.withUsername("lisi").password("456").authorities("p2").build()); 
        return manager; 
    } 

    @Bean 
    public PasswordEncoder passwordEncoder () { 
// //The password is in clear text 
        return NoOpPasswordEncoder.getInstance(); 
// return new BCryptPasswordEncoder(); 
    } 

    //Configure the security interception mechanism 
    protected void configure(HttpSecurity http) throws Exception { 
        http
                .authorizeRequests() 
                .antMatchers("/r/**").authenticated()//Requests starting from /r need to be authenticated. 
                anyRequest().permitAll()//All other requests are allowed.and 
                () 
                .formLogin ().successForwardUrl("/login-success");//Jump to /login-success after successful login 
    } 



}

Restart project

1. Access http://localhost:63070/auth/user/52 and you can access it normally.

2. Visit http://localhost:63070/auth/r/r1 to display the login page.

The account name is zhangsan and the password is 123. If the password entered is incorrect, the authentication will fail. If the password is entered correctly, the login is successful.

Why can http://localhost:63070/auth/user/52  be accessed normally, but the login page is displayed when accessing http://localhost:63070/auth/r/r1 ?

http.logout().logoutUrl("/logout"); The logout page is configured. After successful authentication, you can log out by visiting /logout.

Visit: http://localhost:63070/auth/login.   The port number assigned to my computer is 63070.

 

3. Authorization test

When user authentication is used to access system resources, spring security performs authorization control and determines whether the user has access rights to the resource. If so, access will continue, and if not, access will be denied.

Test the authorization function below:

1. Configure what permissions the user has.

In the WebSecurityConfig class, configure zhangsan to have p1 permissions and lisi to have p2 permissions.

//Configure user information service 
@Bean 
public UserDetailsService userDetailsService() { 
    //Configure user information here, temporarily use this method to store users in memory 
    InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); 
    manager.createUser(User.withUsername(" zhangsan").password("123").authorities("p1").build()); 
    manager.createUser(User.withUsername("lisi").password("456").authorities("p2"). build()); 
    return manager; 
}

2. Specify the relationship between resources and permissions.

What are system resources?

For example: query a user's information. The user information is the resource of the system. To access the resource, you need to pass the URL, so each http interface we define in the controller is the interface for accessing the resource.

Next, configure /r/r1 in the controller to require p1 permissions, and /r/r2 to require p2 permissions.

hasAuthority('p1') means that only those with p1 permission can access.

code show as below:

@RequestMapping("/r/r1") 
@PreAuthorize("hasAuthority('p1')")//Only those with p1 permission can access 
public String r1() { 
    return "Access r1 resources"; 
} 

@RequestMapping("/r /r2") 
@PreAuthorize("hasAuthority('p2')")//Only those with p2 permission can access 
public String r2(){ 
    return "Access r2 resources"; 
}

Now restart the project.

When accessing a URL starting with /r/, it will be judged whether the user is authenticated. If not authenticated, it will jump to the login page. If it has been authenticated, it will be judged whether the user has access rights to the URL. If it has access rights to the URL, continue. Otherwise access is denied.

For example:

To access /r/r1, you can log in with zhangsan and you can access it normally. Because the permission p1 is specified on the /r/r1 method, the zhangsan user has permission p1, so you can access it normally.

Access /r/r1. If you use lisi to log in, access will be denied. Since the lisi user does not have permission p1, access needs to be denied.

Note: If @PreAuthorize is not added to the access, this method has no authorization control.

The process of organizing authorization is shown in the figure below:

4. Working principle

By testing the two functions of authentication and authorization, we have learned the basic usage of Spring Security. Next, we will learn about its workflow.

The problem that Spring Security solves is security access control , and the security access control function is actually to intercept all requests entering the system and verify whether each request can access the resources it expects. According to the previous knowledge learning, it can be achieved through technologies such as Filter or AOP. Spring Security's protection of Web resources is achieved by Filter, so start with this Filter and gradually deepen the principles of Spring Security.

        When Spring Security is initialized, a Servlet filter named SpringSecurityFilterChain will be created, of type org.springframework.security.web.FilterChainProxy, which implements javax.servlet.Filter, so external requests will go through this class, as shown in the figure below Spring Security filter chain structure diagram:

FilterChainProxy is a proxy. What really works are the filters contained in SecurityFilterChain in FilterChainProxy. At the same time, these Filters are managed by Spring as beans. They are the core of Spring Security and each has its own responsibilities, but they do not directly handle user authentication . It does not directly handle user authorization , but hands them over to the authentication manager (AuthenticationManager) and the decision manager (AccessDecisionManager) for processing.

The implementation of the spring Security function is mainly completed by a series of filter chains that cooperate with each other.

The following introduces the main filters in the filter chain and their functions:

SecurityContextPersistenceFilter This Filter is the entrance and exit of the entire interception process (that is, the first and last interceptor). It will obtain the SecurityContext from the configured SecurityContextRepository at the beginning of the request, and then set it to the SecurityContextHolder. After the request is completed, the SecurityContext held by the SecurityContextHolder is saved to the configured SecurityContextRepository, and the SecurityContext held by the securityContextHolder is cleared at the same time;

UsernamePasswordAuthenticationFilter is used to handle authentication from form submissions. The form must provide the corresponding user name and password. It also contains AuthenticationSuccessHandler and AuthenticationFailureHandler for processing after successful or failed login. These can be changed according to needs;

FilterSecurityInterceptor is used to protect web resources. AccessDecisionManager is used to authorize access to the current user, which has been introduced in detail before;

ExceptionTranslationFilter can catch all exceptions from FilterChain and handle them. But it will only handle two types of exceptions: AuthenticationException and AccessDeniedException, and it will continue to throw other exceptions.

The execution flow of Spring Security is as follows:

  1. The user's submitted username and password are obtained by the UsernamePasswordAuthenticationFilter filter in the SecurityFilterChain and encapsulated into a request for Authentication, usually the implementation class UsernamePasswordAuthenticationToken.
  1. The filter then submits the Authentication to the authentication manager (AuthenticationManager) for authentication
  1. After successful authentication, the AuthenticationManager identity manager returns an Authentication instance filled with information (including the permission information, identity information, and details mentioned above, but the password is usually removed).
  1. The SecurityContextHolder security context container sets the Authentication filled with information in step 3through the SecurityContextHolder.getContext().setAuthentication(...) method.
  1.         It can be seen that the AuthenticationManager interface (authentication manager) is the core interface related to authentication and the starting point for initiating authentication. Its implementation class is ProviderManager. Spring Security supports multiple authentication methods, so ProviderManager maintains a List<AuthenticationProvider> list to store multiple authentication methods. In the end, the actual authentication work is completed by AuthenticationProvider. We know that the corresponding AuthenticationProvider implementation class of the web form is DaoAuthenticationProvider, which maintains a UserDetailsService internally and is responsible for obtaining UserDetails. Finally, the AuthenticationProvider populates the UserDetails into the Authentication.

 

Guess you like

Origin blog.csdn.net/Relievedz/article/details/129581260