基于RBAC的权限访问系统(SpringBoot+SpringSecurity+Mybatis)

需要,基于RBAC的权限访问,采用SpringSecurity安全管理框架+SpringBoot+Mybatis数据库持久框架。

数据库设计:

user用户名:ennabled,accountNonExpired,accountNonLocked,CredentialsNonExpired默认为1

role角色表:

permisson权限表:

user_role 用户-角色中间表:

role_permission色色-权限中间表:

permission表中初始数据,权限名为permTag

编码实现:

1.pom.xml,引入了jdbc,thymeleaf,security,web,mybatis,devtools,lombox,mysql

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>2.3.1.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

2.application.properties

#数据库连接,暂时未使用数据库连接池
spring.datasource.url=jdbc:mysql://localhost:3306/yderp
spring.datasource.username=root
spring.datasource.password=a61322799
#开发期间不需要缓存模板
spring.thymeleaf.cache=false

3.资源文件,其中main.html为需要权限才能访问的页面 

reg.html

<form action="/reg" method="post">
    用户名<input type="text" name="username"/> <br/>
    用户名<input type="text" name="realname"/> <br/>
    密码 <input type="password" name="password"/><br/>
    <input type="submit" value="注册">
</form>

login.html

<!--name值:必须为username password-->
<form method="post" action="/login">
    用户名:<input type="text" name="username">
    密码<input type="text" name="password">
    <input type="submit" value="登录">
</form>
<!-- MySecurity类中 .failureUrl("/login?error=true")-->
<label style="color: red" th:if=${param.error} th:text="账户密码错误,请重新登录"></label>
</body>

index.html

<body>
this is Main page!
<a href="/main">权限页面</a>
<a href="/logout">注销</a>
</body>

 main.html

<body>
本页面需要权限访问
<a href="/logout">注销</a>
</body>

4.实体类domain

//角色实现UserDetails接口实现用户的封装
@Data
public class User  implements UserDetails {
    private int id;
    private String username;
    private String realname;
    private String password;
    private LocalDate createDate;
    private LocalDateTime lastLoginTime;
    //账户是否不可用,数据库为1代表true,0代表false,默认为1
    private boolean enabled;
    //账户是否未过期
    private boolean accountNonExpired;
    //账户是否锁定
    private boolean accountNonLocked;
    //密码是否未过期
    private boolean credentialsNonExpired;
    //权限集合
    private List<GrantedAuthority>  authorities;
}

@Data
public class Role {
    private int id;
    private String roleName;
    private String roleDesc;
}

@Data
public class Permission {
    private int id;
    private String permName;
    //权限标志符,authorities集合的值
    private String permTag;
}

5.数据库查询dao接口

@Mapper
@Component
public interface UserDao {
    //用户名查询用户信息
    @Select("select * from user where userName = #{userName}")
    public User selectByUserName(String userName);
    //用户名查询当前用户的权限信息
    @Select("select permission.* FROM" +
            "    user  u" +
            "    INNER JOIN user_role ON u.id = user_role.uid" +
            "    INNER JOIN role_permission on user_role.rid = role_permission.rid" +
            "    INNER JOIN permission on role_permission.pid = permission.id" +
            "    WHERE u.username = #{userName};")
    public List<Permission> findPermissionByUserName(String userName);
    //注册用户
    @Insert("insert into user values(default,#{user.username}," +
            "#{user.realname},#{user.password},now(),now(),default,default,default,default)")
    int insert(@Param("user") User user);
}

6.UserService

public interface UserService {
    public int insert(User user);
}

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao =null;
    @Override
    public int insert(User user) {
        return userDao.insert(user);
    }
}

7.MyController注册

@Controller
public class MyController {
    @Autowired
    UserService userService = null;
    //用户注册
    @RequestMapping("/reg")
    @ResponseBody
    public String reg(User user){
        System.out.println(user);
        String pwd = user.getPassword();
        //加密,springSecurity现在默认要强制加密
        pwd = new BCryptPasswordEncoder().encode(pwd); 
        user.setPassword(pwd);
        int insert = userService.insert(user);
        if(insert > 0){
            return "注册成功";
        }
        return "注册失败";
     }
}

8.springMVC config配置

@Configuration
public class MyConfig implements WebMvcConfigurer {
   //静态资源URI和位置映射
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/");
    }
    //视图映射
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/login").setViewName("login");
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/403").setViewName("403");
        registry.addViewController("/main").setViewName("main");
    }
}

9.权限不足逻辑跳转

@Configuration
public class ErrorPageConfig implements ErrorPageRegistrar  {
    @Override
    public void registerErrorPages(ErrorPageRegistry registry) {
        //权限不足的页面导向
        ErrorPage error403 = new ErrorPage(HttpStatus.FORBIDDEN,"/403");
        registry.addErrorPages(error403);
    }
}

10.UserDetailsService接口的实现

@Service
public class MyUserDetalisService implements UserDetailsService {
    @Autowired
    UserDao userDao = null;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //查询当前用户信息
        User user = userDao.selectByUserName(username);
        //查询当前用户权限
        List<Permission> list = userDao.findPermissionByUserName(username);
        List<GrantedAuthority> authorities = new ArrayList<>();
        /*
        * 将getPermTag()构建一个GrantedAuthority接口实例对象,放于List<GrantedAuthority>中
        * */
        list.forEach(l ->{
            authorities.add(new SimpleGrantedAuthority(l.getPermTag()));
        });
        //用户信息设置权限集合
        user.setAuthorities(authorities);
        return user;
    }
}

11.springSecurity配置,重点

@EnableWebSecurity
public class MySecurity extends WebSecurityConfigurerAdapter {
    @Autowired
    MyUserDetalisService myUserDetalisService = null;

    //http安全配置
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()  //所有请求拦截
         .antMatchers("/static/**").permitAll() //放在所有拦截的前面放行不需要拦截的资源
         .antMatchers("/login").permitAll()  //放行登录
         .antMatchers("/logout").permitAll() //放行注销
         .antMatchers("/reg").permitAll()  //放行注册
         .antMatchers("/main").hasAnyAuthority("ROLE_PRODUCT_LIST")//此页需要权限
         .anyRequest().authenticated() //除上所有拦截需要用户认证 
            .and()
                .formLogin().loginPage("/login") //forlogin认证
                .failureUrl("/login?error=true")//登陆错误页
            .and()
                .csrf().disable(); //关闭csrf校验

    }
    //认证管理器配置
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetalisService)
                //查询时需要密码加密后和数据库做比较
                .passwordEncoder(new BCryptPasswordEncoder());
    }
}

 


版权声明:本文为u011573295原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。