基于RBAC的权限访问系统基础
需要,基于RBAC的权限访问,采用SpringSecurity安全管理框架+SpringBoot+Mybatis数据库持久框架。
数据库设计:
user用户名:ennabled,accountNonExpired,accountNonLocked,CredentialsNonExpired默认为1
role角色表:
permission权限表:
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()); } }