As long as the system that deals with the user basically needs to carry on authority management, otherwise which day operation undeserved to delete the library to you how to do. Open source authority management framework has SpringSecurity, Shiro, authority management model has RBAC, ACL, etc. It is better to choose the open source framework or to build wheels based on the authority management model. It is necessary to investigate and choose a suitable way to implement the company’s business. First of all, research and learn a wave of SpringSecurity

Through this article you will find out

  • SpringSecuritySome core classes in
  • useSpringSecurityRole-based permission verification
  • SpringSecurityThe shortage of the

SpringSecurity core classes

Because SpringSecurity is an investigative study, there will be no introduction to the source code. Permission management is authorization, authentication, authentication must first login to get user information, but here will not talk about login, logout and distributed session management, only introduce the authentication process of the core class, understand the core class can quickly integrate SpringSecurity framework.

Log in check
  • UsernamePasswordAuthenticationFilter=> User login verification, but this class does not actually do login verification, but through the ProviderManager
  • ProviderManager=> There is one in this classList<AuthenticationProvider>, provides different verification methods, as long as one of them passes. Usually we don’t deserve anything based on the username and password, rightAuthenticationProviderThe implementation class forAbstractUserDetailsAuthenticationProvider
  • AbstractUserDetailsAuthenticationProvider=> Its login verification is by subclassadditionalAuthenticationChecksMethod accomplished
  • DaoAuthenticationProvider= >AbstractUserDetailsAuthenticationProviderIf the password we set (either memory based or database based) does not match the passed password, login verification fails
  • UserDetailsService=> the only way through this interfaceloadUserByUsernameReturn user information such as username and password that we set (Is encapsulated asUserDetailsThe implementation of the class)

Summary: Login authentication takes the username and password of the client and compares it to the username and password we set up (the implementation class of UserDetails). Get we set user name password is through UserDetailsService loadUserByUsername (String userName) implementation/highlight, one would want to take an examination of, UserDetailsService framework implementations generally can not meet the project requirement, We need to implement UserDetails manually, and we can also implement UserDetails ourselves if the framework’s own implementation class does not meet the requirements

Permission to check
  • FilterSecurityInterceptorCheck the interceptor based on the role, calling the parent classAbstractSecurityInterceptorthebeforeInvocationMethod to authenticate
  • AbstractSecurityInterceptor= > callAccessDecisionManagerThe implementation classdecideMethod, so how do you customize the authentication method by writing a class and implementing itAccessDecisionManager
  • AffirmativeBased=> Used by defaultAccessDecisionManagerImplementation class, callAccessDecisionVoterImplement class vote method for authentication, return 1 permission check passed, in fact, trace to the end actually or compare string can not be said to vote, method name is easy to misunderstand
  • WebExpressionVoter=> Used by defaultAccessDecisionVoterImplementation class, callThe Authentication of the AuthenticationMethod to authenticate
  • SecurityExpressionOperations= > accessAuthenticationObject interface
  • SecurityExpressionRoot= >SecurityExpressionOperationsThe implementation class

Summary: Generally we do not have to customize the authentication method of these we can ignore, although layers call many layers, in fact, is to determine whether the current user contains permissions in the list of access to the specified URL required permissions

Integrate SpringBoot SpringSecurity

Rely on
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> < version > 1.4.1. RELEASE < / version > < / dependency >Copy the code
UserDetails implementation class: userTo.java
Public class UserDTO implements UserDetails {/** * username ** / private String username; /** * private String password; /** * private List<String> roleList; public voidsetUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public List<String> getRoleList() {
        return roleList;
    }

    public void setRoleList(List<String> roleList) {
        this.roleList = roleList;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> authorityList = new ArrayList<>();
        for (String role : roleList) {
            authorityList.add(new SimpleGrantedAuthority(role));
        }

        return authorityList;
    }

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

    @Override
    public String getUsername() {
        return 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; }}Copy the code

SimpleGrantedAuthority is an implementation class of GrantedAuthority. If the default implementation does not meet the requirements, you can re-implement it yourself. UserDetail is the bridge between SpringSecurity and your application. No matter how you build your database, as long as you finally encapsulate the relationship between user information and permissions as UserDetails, SpringSecurity can verify permissions according to its own mechanism, right

UserDetailsService implementation class: UserDetailsServiceImpl. Java
public class UserDetailsServiceImpl implements UserDetailsService { @Resource private UsersService usersService; / * * * according to the user name for user information * / @ Override public populated UserDetails loadUserByUsername (String username) throws UsernameNotFoundException {  Users users = new Users(); users.setUsername(username); List<Users> usersList = usersService.selectList(users);returnbuildUserDTO(usersList); } /** * encapsulates the UserDTO object ** @param usersList * @return
     * */
    private UserDTO buildUserDTO(List<Users> usersList) {
        UserDTO userDTO = new UserDTO();
        userDTO.setUsername(usersList.get(0).getUsername());
        userDTO.setPassword(usersList.get(0).getPassword());
        List<String> roleList = new ArrayList<>();
        for (Users users : usersList) {
            roleList.add(String.format("ROLE_%s", users.getRole()));
        }

        userDTO.setRoleList(roleList);
        returnuserDTO; }}Copy the code

This class is used to retrieve user information and permission information from the database and encapsulate it into a UserDetails return

Permission configuration class: webSecurityconfig.java
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) / / opening method level security verification public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@autowired private UserDetailsServiceImpl userDetailsService; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyrequest ().authenticated() // anyRequest that can be accessed after login. And ().formlogin ().permitall (); CSRF cross-domain http.csrf().disable(); } @override public void configure(WebSecurity web) throws Exception {// Ignoring ().antmatchers ()"/css/**"."/js/**"."/templates/**"); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //1. Set a user-defined userDetailService //2. Specify the password decoding mode auth.userDetailsService(userDetailsService). PasswordEncoder (new) BCryptPasswordEncoder()); }}Copy the code

This class configures the login page and some simple permission Settings, such as any request login can be accessed, the login page can be accessed by all. Because by @ EnableGlobalMethodSecurity annotations opens the method level verification, in this way do not have permission to configure method level. Specify the UserDetailsService and the password decoding mode. If you do not specify the password decoding mode, an error will be reported in the latest version of SpringSecurity

Controls how layer annotations are used

@RestController
@RequestMapping("/api/user")
public class UsersController {
    @GetMapping("/guest")
    @PreAuthorize("hasAnyRole('guest')")
    public Object guest() {
        return "hello guest";
    }

    @PreAuthorize("hasAnyRole('admin')")
    @GetMapping("/admin")
    public Object admin() {
        return "hello admin"; }}Copy the code

Permissions are controlled by @preauthorize, and permissions (roles) that access the API are written in hasAnyRole. In addition to @preauthorize, you can also use @secured and @Postauthorize

Shortcomings of the SpringSecurity framework

  • There was an intrusion into the project code

  • All systems that require permission verification need to integrate The SpringSecurity framework. Different application systems have different database designs, and UserDetail generally needs to be implemented by itself.

  • Roles should be dynamic, but roles configured with SpringSecurity are static and must be modified when new roles are added to the database, otherwise they cannot be used

  • It is not an RBAC design model but an ACL model. The division of role permissions is not particularly clear. Permissions can also be roles

  • The permission management granularity is not fine enough. For example, permission verification at the method level is not supported. To support more fine-grained permission verification, you must write permission verification by yourself

  • Provide three cache user information, NullUserCache, EhCacheBasedUserCache, SpringCacheBasedUserCache respectively. The first method is always return NULL, which means that the cache is not used. The latter two methods are in-memory caches. In distributed deployment, the cache hit ratio is low and the caches are inconsistent

    Just some of their own views, if there is a mistake welcome correction

Finally, attached: project source code