Use SpringSecurity in SpringBoot

@

This tutorial was created based on SpringMVC and does not apply to WebFlux. (If you do n’t know the two, you can ignore this prompt)

Raise a demand

All the technologies have emerged to solve practical problems, so we are not empty talk, nor do we talk about so many concepts. In such a system, there are three interfaces that need to be authorized to be used by people with three permissions, as shown in the following table:

interface address Required permission description Accessible group name
visitor/main No permission, no login, anyone can access
admin/main Must log in, only administrators can access ADMIN
user/main Must be logged in, both administrator and user rights can access USER和ADMIN

solution:

  • Determine whether the user is logged in and the user's permission group in the Controller to determine whether it can be accessed

    This is the most unrealistic solution, but the project that I designed when I first joined the company was designed like this. At the time, I still felt very noble.

  • Use the three components of the web application to neutralize the filter

    This is a positive solution, and SpringSecurity also uses this principle. If your project is simple enough, it is recommended that you use this method directly, and does not need to integrate SpringSecurity. The examples in this part are demonstrated in the code, you can download the code to view it.

  • We can directly use the SpringSecurity framework to solve this problem

Use SpringSecurity to solve

There are so many online tutorials, but they are unclear. So, please read these words carefully in the next paragraph, which is more important than the code behind.

SpringSecurity mainly has two parts:

  • Authentication (Who are you, bluntly is a user login function, help us verify the user name and password)
  • Authorization (What you can do is to indicate which interfaces you can access and which ones you cannot access based on the permissions of the currently logged in user.)

The login here is for browser access, because if the front-end and back-end are separated, the token is used for authorization, which can also be understood as the logged-in user, which will be described later. This is mentioned here only for the rigor of knowledge

Combination of SpringSecurity and SpringBoot

1. First introduce dependencies in pom.xml:

<!-- 不用写版本,继承Springboot的版本-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>

2. Configure the permission relationship between user roles and interfaces

It supports configuration using XML, but it is more recommended to use Java annotation configuration in Spring Boot

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * 配置用户权限组和接口路径的关系
     * 和一些其他配置
     *
     * @param http
     * @throws Exception
     */
    @Override
     protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()     // 对请求进行验证
                .antMatchers("/visitor/**").permitAll()
                .antMatchers("/admin/**").hasRole("ROLE_ADMIN")     // 必须有ADMIN权限
                .antMatchers("/user/**").hasAnyRole("ROLE_USER", "ROLE_ADMIN")       //有任意一种权限
                .anyRequest()     //任意请求(这里主要指方法)
                .authenticated()   //// 需要身份认证
                .and()   //表示一个配置的结束
                .formLogin().permitAll()  //开启SpringSecurity内置的表单登录,会提供一个/login接口
                .and()
                .logout().permitAll()  //开启SpringSecurity内置的退出登录,会为我们提供一个/logout接口
                .and()
                .csrf().disable();    //关闭csrf跨站伪造请求
    }

}

There are two main contents of the above configuration:

  1. Configure the permissions required to access three interfaces (actually more than three, / ** refers to the general term);
  2. Configured to use SpringSecurity's built-in / login and / loginout interfaces (this is completely customizable)
  3. The return result after permission is denied can also be customized, it will throw an exception when permission is denied

Description:

  1. In the configuration above, it is actually a method of calling this object of http;
  2. Use .and () only to indicate the end of the configuration and meet the requirements of chained call, otherwise the previous object may not be able to make chained call
  3. This configuration will be called when the Spring Boot application starts, that is, these configurations will be loaded into memory. When the user calls the corresponding interface, it will determine whether its role can call this interface. The flow chart is as follows (I think the figure To explain the process better than the text):

3. Configure username and password

After configuring the relationship between the above interface and the user rights role, we need to configure our user name and password. If you do not have the correct user name and password, Shenxian cannot log in.

About this, the online tutorial has a variety of configurations. In fact, it is an interface. We only need to implement the methods in this interface. The interface code is as follows:

package org.springframework.security.core.userdetails;

public interface UserDetailsService {
  	/**
  	 * 在登录的时候,就会调用这个方法,它的返回结果是一个UserDetails接口类
  	 */
    UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}

Look at this interface, if you want to extend, you can write an implementation class yourself, or you can use the implementation provided by SpringSecurity

public interface UserDetails extends Serializable {
  	// 用户授权集合
    Collection<? extends GrantedAuthority> getAuthorities();
    String getPassword();
    String getUsername();
    boolean isAccountNonExpired();
    boolean isAccountNonLocked();
    boolean isCredentialsNonExpired();
    boolean isEnabled();
}

Implementation class of UserDetailsServicer interface

@Configuration
public class UserDetailsServiceImpl implements UserDetailsService {
    /**
     * 这个方法要返回一个UserDetails对象
     * 其中包括用户名,密码,授权信息等
     *
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        /**
         * 将我们的登录逻辑写在这里
         * 我是直接在这里写的死代码,其实应该从数据库中根据用户名去查
         */
        if (username == null) {
            //返回null时,后边就会抛出异常,就会登录失败。但这个异常并不需要我们处理
            return null;
        }
        if (username.equals("lyn4ever")) {
            //这是构造用户权限组的代码
            //但是这个权限上加了ROLE_前缀,而在之前的配置上却没有加。
            //与其说这不好理解,倒不如说这是他设计上的一个小缺陷
            SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
            List<SimpleGrantedAuthority> list = new ArrayList<>();
            list.add(authority);
            //这个user是UserDetails的一个实现类
            //用户密码实际是lyn4ever,前边加{noop}是不让SpringSecurity对密码进行加密,使用明文和输入的登录密码比较
            //如果不写{noop},它就会将表表单密码进行加密,然后和这个对比
            User user = new User("lyn4ever", "{noop}lyn4ever", list);
            return user;
        }
        if (username.equals("admin")) {
            SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
            SimpleGrantedAuthority authority1 = new SimpleGrantedAuthority("ROLE_ADMIN");
            List<SimpleGrantedAuthority> list = new ArrayList<>();
            list.add(authority);
            list.add(authority1);
            User user = new User("admiin", "{noop}admin", list);
            return user;
        }

        //其他返回null
        return null;
    }
}

4. Perform the test

Access the three interfaces above, you can see that the access results are the same as the above process.

to sum up:

  • Read the flowchart above carefully to understand the most important content of SpringSecurity. The code is very simple; there are two classes above, one is the relationship between the configuration interface and the role, and the other implements the methods in the UserDetailsService class.
  • As mentioned earlier, SpringSecurity is mainly two logic:
    • After the user logs in, save the user's role information in the server (session);
    • After the user accesses the interface, the user information is taken from the session, and then compared with the configured roles and permissions to see if there is this permission to access
  • In the above method, we only rewritten the logic when the user logged in. We have not modified whether the current user has access to this interface according to the access interface. So this only applies to projects that can use session.
  • For projects with separate front and back ends, JWT is generally used for authorization, so its main content is to determine whether the information in the token has permission to access this interface, not the user login part.
  • There are many ways to solve the visit, and it is best to choose what suits you best. SpringSecurity only provides a series of interfaces, and he also has some internal implementations, which you can also use directly.
  • The content of the above configuration and user login logic can be completely queried from the database for configuration.

Code address

Guess you like

Origin www.cnblogs.com/Lyn4ever/p/12709953.html