SpringSecurity rights management [articles]

As long as the system and users need to be dealing with basic rights management, or improper operation to the day you delete the database how to do. Rights management framework open source has SpringSecurity, Shiro, rights management model has RBAC, ACL, etc., is to choose an open source framework for better or based rights management model was built wheels must research about the election of a suitable implementation of the company's business, first of all first research study wave SpringSecurity

By this article you will learn

  • SpringSecuritySome core classes
  • Use SpringSecurityrole-based permissions check
  • SpringSecurityShortage

SpringSecurity core classes

Because SpringSecurityonly the research of learning, so there will not have the source code introduced. Rights Management is authorized, authentication, authorization must first sign in order to get user information, but will not be here to talk login, logout and distributed sessionmanagement, will introduce the authentication process of core classes to learn about core classes can be quickly integrated SpringSecurityframework.

Log parity
  • UsernamePasswordAuthenticationFilter => User login authentication, but this class is really not to carry out landing check, but by ProviderManager
  • ProviderManager=> There is a class List<AuthenticationProvider>, a different parity, as long as one can pass. Under normal circumstances we do not deserve what is the user name and password, this time AuthenticationProviderto achieve classAbstractUserDetailsAuthenticationProvider
  • AbstractUserDetailsAuthenticationProvider=> Which is obtained by checking the landing subclass additionalAuthenticationChecksmethod completed
  • DaoAuthenticationProvider=> AbstractUserDetailsAuthenticationProviderThe only sub-category, if we set a password (may be based on memory-based database) and pass over the password validation does not check failed on landing
  • UserDetailsService=> Only way through this interface loadUserByUsernamereturns the user such as user name and password information that we have set ( packaged as UserDetailsimplementation class )

Summary: Login Username Password verification is to get the client's user name and password we set (that is, UserDetailsthe implementation class) for comparison, to get the username and password are set by our UserDetailsService.loadUserByUsername(String userName)realization of [the focus of planning, one would have to test] , the framework to achieve the UserDetailsServicegeneral can not meet the project requirements, you need to manually achieved, if at the same time frame that comes with UserDetailsthe realization of the class can not meet the requirements, we can also realize his UserDetails

Check permissions
  • FilterSecurityInterceptor=> Role-based permissions check blocker, call the parent class AbstractSecurityInterceptor's beforeInvocationmethod for authentication
  • AbstractSecurityInterceptor=> Call the AccessDecisionManagerimplementation class of decidemethods for authentication, so how want to customize the way authentication can write a class and then implementAccessDecisionManager
  • AffirmativeBased=> Use the default AccessDecisionManagerimplementation class, calls the AccessDecisionVotervote for authentication method implementation class, returns a permission check by actually tracking the end but it is still more than the string can not be said to vote now, the method name is misleading
  • WebExpressionVoter=> Use the default AccessDecisionVoterimplementation class, call the Authentication的authenticationmethod for authentication
  • SecurityExpressionOperations=> Get AuthenticationObject Interface
  • SecurityExpressionRoot=> SecurityExpressionOperationsImplementation class

Summary: Custom authentication is generally not the way, then we may not need these tubes, although the layers of calling a lot of layers, in fact, the essence is to determine the rights of the current user list included whether to include access to the url needed

SpringBoot integration SpringSecurity

rely
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    <version>1.4.1.RELEASE</version>
</dependency>
复制代码
UserDetails implementation class: UserDTO.java
public class UserDTO implements UserDetails {
    /**
     * 用户名
     * */
    private String username;

    /**
     * 密码
     * */
    private String password;

    /**
     * 角色列表
     * */
    private List<String> roleList;

    public void setUsername(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;
    }
}
复制代码

Implementation class needs to implement the interface, where we will inquire into the roleListstring encapsulated SimpleGrantedAuthorityin, SimpleGrantedAuthorityit is GrantedAuthoritythe realization of a class, if the default implementation can not meet the needs of their own re-implemented. UserDetailIs SpringSecuritya bridge between the application and, no matter how you build the database, as long as your last relationship will package the user information and permissions for UserDetails, SpringSecurityyou can check permissions according to its own mechanisms

UserDetailsService implementation class: UserDetailsServiceImpl.java
public class UserDetailsServiceImpl implements UserDetailsService {
    @Resource
    private UsersService usersService;

    /**
     * 根据用户名获取用户信息
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Users users = new Users();
        users.setUsername(username);
        List<Users> usersList = usersService.selectList(users);

        return buildUserDTO(usersList);
    }

    /**
     * 封装UserDTO对象
     *
     * @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);
        return userDTO;
    }
}
复制代码

This class action is to find the right information and user information from the database to the package as a UserDetailsreturn

Permissions configuration class: WebSecurityConfig.java
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // 开启方法级安全验证
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated() //任何请求,登录后可以访问
                .and().formLogin().permitAll(); //登录页面用户任意访问

        // 关闭CSRF跨域
        http.csrf().disable();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        // 设置拦截忽略文件夹,可以对静态资源放行
        web.ignoring().antMatchers("/css/**", "/js/**", "/templates/**");
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //1.设置自定义userDetailService
        //2.校验时指定密码解码方式
        auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }
}
复制代码

This class is well equipped with landing pages and some simple permission settings, such as access to any request after landing, everyone can access the login page. Because by the @EnableGlobalMethodSecurityopen method of verifying the level of annotation, method-level permission is not configured In this method. At the same time achieved by specifying their own UserDetailsServiceand password to decode the way, if you do not specify a password will be thrown in the way of decoding the latest SpringSecurityversion

Use control layer annotations

@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";
    }
}
复制代码

Through @PreAuthorizeto access control, the hasAnyRoleaccess to the api has permission (role) is written, in addition to using @PreAuthorizenotes, you can also use @Secured, @PostAuthorizeannotations

Insufficient SpringSecurity framework

  • Project code has invaded

  • Not general enough, all the required permissions verification systems require integration SpringSecurityframework, different application systems database design, UserDetailit generally takes to achieve their own [just an example, the actual development process to rewrite the class probably more]

  • Role should be dynamic, but by SpringSecuritythe role configuration is static, you must modify the code in the database added a new role, otherwise it can not be used

  • Not a RBACdesign model but a ACLmodel, clarify roles privileges not particularly clear, the role of authority may be, if you want based on RBACthe permissions check must re-write their own permission check method

  • Rights management granularity is not detailed enough, can not support such a method to check the level of authority, I want to support more fine-grained permissions must write their own check permissions

  • Three ways to cache user information provided, respectively NullUserCache, EhCacheBasedUserCache, SpringCacheBasedUserCache. The first forever return null, the equivalent of not using the cache, the latter two are memory cache, the cache hit rate will appear in a distributed deployment, the cache inconsistency, the need to implement cache

    Only some of his views, please correct me if flawed

Last Attachment: Project Source

Guess you like

Origin juejin.im/post/5d7516f951882559c4162b05