基于SpringSecurity实现RBAC权限控制

基于SpringSecurity实现RBAC权限控制

mapper

package com.po.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.po.domain.Permission;
import org.apache.ibatis.annotations.Select;

import java.util.List;


public interface PermissionMapper extends BaseMapper<Permission> {
    /**
     * 根据用户ID查询权限
     *
     * @param id
     * @return
     */
    @Select("SELECT p.*  FROM t_permission p,t_role_permission rp,t_role r,t_user_role ur,t_user u " +
            "WHERE p.id = rp.PID AND rp.RID = r.id AND r.id = ur.RID AND ur.UID = u.id AND u.id =#{id}")
    List<Permission> findByUserId(Integer id);
}

 service

package com.po.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.po.domain.Permission;

import java.util.List;

public interface PermissionService extends IService<Permission> {
    // 根据用户ID查询对应的权限
    List<Permission> findByUserId(Integer id);
}

 

package com.po.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.po.domain.Permission;
import com.po.mapper.PermissionMapper;
import com.po.service.PermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 权限Service
 */
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements PermissionService {

    @Autowired
    PermissionMapper permissionMapper;

    /**
     * 根据用户ID查询权限列表
     *
     * @return
     */
    @Override
    public List<Permission> findByUserId(Integer id) {
        return permissionMapper.findByUserId(id);
    }
}

userdetailservice

package com.po.service.impl;

import com.po.domain.MyUserDetails;
import com.po.domain.Permission;
import com.po.domain.User;
import com.po.mapper.MyUserDetailsServiceMapper;
import com.po.service.PermissionService;
import com.po.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

@Component
public class MyUserDetailsService implements UserDetailsService {

    @Resource
    private PermissionService permissionService;

    @Resource
    private UserService userService;

    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {
        User user = userService.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("user is ==>" + username);
        }
        // 先声明一个权限集合, 因为构造方法里面不能传入null
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        List<Permission> permissionList= permissionService.findByUserId(user.getId());
        for (Permission permission : permissionList) {
            authorities.add(new SimpleGrantedAuthority(permission.getPermissionTag()));
        }
        UserDetails userDetails = new org.springframework.security.core.userdetails.User(username,
                "{bcrypt}"+user.getPassword(),//不使用密码加密
                true, //用户是否启用 (true:启用)
                true,//用户是否过期 (true:没有过期)
                true, //用户凭证是否过期 (true:没有过期)
                true, // 用户是否锁定 (true:没有锁定)
                authorities);
        return userDetails;

        }
}

给登录用户进行授权

package com.po.config;

import com.po.domain.Permission;
import com.po.filter.ValidateCodeFilter;
import com.po.handler.MyAccessDeniedHandler;
import com.po.service.PermissionService;
import com.po.service.impl.MyAuthenticationService;
import com.po.service.impl.MyUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.List;


@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启注解支持
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyUserDetailsService myUserDetailsService;

    @Autowired
    ValidateCodeFilter validateCodeFilter;

    @Autowired
    MyAccessDeniedHandler accessDeniedHandler;


    @Resource
    private PermissionService permissionService;

    /**
     * http请求方法
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        /** http.httpBasic() //开启httpBasic认证
         .and().authorizeRequests().anyRequest().authenticated(); //所有请求都需要认证之后访问
         */
        // 将验证码过滤器添加在UsernamePasswordAuthenticationFilter过滤器的前面
        http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class);

        // 设置/user/** 访问需要ADMIN角色
       // http.authorizeRequests().antMatchers("/user/**").hasRole("ADMIN");
        //使用自定义Bean授权
/*        http.authorizeRequests().antMatchers("/user/**").
                access("@myAuthorizationService.check(authentication,request)");*/

        //使用自定义Bean授权,并携带路径参数
/*        http.authorizeRequests().antMatchers("/user/delete/{id}").
                access("@myAuthorizationService.check(authentication,request,#id)");*/

        //查询数据库所有权限列表
        List<Permission> permissionList=permissionService.list();
        for (Permission permission : permissionList) {
            //添加请求权限
            http.authorizeRequests().antMatchers(permission.getPermissionUrl())
                    .hasAuthority(permission.getPermissionTag());
        }

        // 设置自定义权限不足信息.
        http.exceptionHandling().accessDeniedHandler(accessDeniedHandler);


/*        http.formLogin().loginPage("/login.html")//开启表单认证
              //  .and().authorizeRequests() //放行登录页面
            //    .anyRequest().authenticated();
             //   .and().authorizeRequests().antMatchers("/login.html").permitAll() //放行登录页面
                .and().authorizeRequests().antMatchers("/toLoginPage").permitAll() //放行登录页面
                .anyRequest().authenticated();*/
                 http.formLogin() //开启表单认证
                .loginPage("/toLoginPage") // 自定义登陆页面
                .loginProcessingUrl("/login") //表单提交路径
                .usernameParameter("username").passwordParameter("password") //自定义input额name值和password
                .successForwardUrl("/") //登录成功之后跳转的路径
                         .successHandler(myAuthenticationService) // 登录成功处理
                         .failureHandler(myAuthenticationService) //登录失败处理
                         .and().logout().logoutUrl("/logout") //退出
                         .logoutSuccessHandler(myAuthenticationService) //退出后处理
                .and().authorizeRequests().antMatchers("/toLoginPage").permitAll() //放行登录页面
                .anyRequest().authenticated()
                 .and().rememberMe() //开启记住我功能
                  .tokenValiditySeconds(1209600) //token失效时间,默认失效时间是两周
                  .rememberMeParameter("remember-me") // 自定义表单name值
                  .tokenRepository(getPersistentTokenRepository()) //设置PersistentTokenRepository
                 .and().headers().frameOptions().sameOrigin() //加载同源域名下iframe页面
                .and().csrf().disable();//关闭csrf防护
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        //解决静态资源被拦截的问题
        web.ignoring().antMatchers("/css/**","/images/**","/js/**","/code/**");
    }

    /**
     *身份安全管理器
     * @param auth
     * @throws Exception
     */
    /*
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService);
    }*/

    @Autowired
    DataSource dataSource;
    /**
     * 负责token与数据库之间的操作
     * @return
     */
    @Bean
    public PersistentTokenRepository getPersistentTokenRepository(){
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource); //设置数据源
        tokenRepository.setCreateTableOnStartup(false); //启动时帮助我们自动创建一张表,第一次启动设置为true,第二次启动程序的时候设置false或者注释掉;
        return tokenRepository;
    }

    @Autowired
    private MyAuthenticationService myAuthenticationService;

/*    @Bean("passwordEncoder")
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }*/

    @Resource
    private MyUserDetailsService userDetailsService;


    /**
     * 身份安全管理器
     * @param builder
     * @throws Exception
     */
   @Override
    protected void configure(AuthenticationManagerBuilder builder) throws Exception {
        builder.userDetailsService(userDetailsService)
               ;
    }

}

 

posted @ 2023-03-17 09:44  __破  阅读(189)  评论(0)    收藏  举报