一、RBAC权限模型表设计
可参考:基于Security的RBAC权限控制数据库模型设计
二、环境依赖
1)、核心pom依赖
<!-- springboot整合freemarker -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-->spring-boot 整合security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- springboot 整合mybatis框架 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!-- alibaba的druid数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.9</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- SpringBoot整合Web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2)、yml配置
server:
port: 9001
# 配置freemarker
spring:
freemarker:
# 设置模板后缀名
suffix: .ftl
# 设置文档类型
content-type: text/html
# 设置页面编码格式
charset: UTF-8
# 设置页面缓存
cache: false
# 设置ftl文件路径
template-loader-path:
- classpath:/templates
# 设置静态文件路径,js,css等
mvc:
static-path-pattern: /static/**
####整合数据库层
datasource:
name: test
url: jdbc:mysql://127.0.0.1:3306/zhq_test_security
username: root
password: root
# druid 连接池
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
三、案例代码
1)、entity案例代码
注意:User类需要实现Security中的UserDetails的getAuthorities()方法
// 用户信息表
@Data
public class User implements UserDetails {
private Integer id;
private String username;
private String realname;
private String password;
private Date createDate;
private Date lastLoginTime;
private boolean enabled;
private boolean accountNonExpired;
private boolean accountNonLocked;
private boolean credentialsNonExpired;
// 用户所有权限
private List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
}
// 角色信息表
@Data
public class Role {
private Integer id;
private String roleName;
private String roleDesc;
}
@Data
public class Permission {
private Integer id;
// 权限名称
private String permName;
// 权限标识
private String permTag;
// 请求url
private String url;
}
2)、mapper案例代码
public interface UserMapper {
// 查询用户信息
@Select(" select * from sys_user where username = #{userName}")
User findByUsername(@Param("userName") String userName);
// 查询用户的权限
@Select(" select permission.* from sys_user user" + " inner join sys_user_role user_role"
+ " on user.id = user_role.user_id inner join "
+ "sys_role_permission role_permission on user_role.role_id = role_permission.role_id "
+ " inner join sys_permission permission on role_permission.perm_id = permission.id where user.username = #{userName};")
List<Permission> findPermissionByUsername(@Param("userName") String userName);
}
public interface PermissionMapper {
@Select(" select * from sys_permission ")
List<Permission> findAllPermission();
}
3)、service案例代码
注意:需要实现Security中的UserDetailsService 的loadUserByUsername()方法
@Component
public class MyUserDetailService implements UserDetailsService {
@Autowired
private UserMapper userMapper;
/**
* 查询用户信息
* @param username 用户名
* @return UserDetails
* @throws UsernameNotFoundException 用户找不到
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 根据用户查询用户信息
User user = userMapper.findByUsername(username);
// 根据用户查询用户对应权限
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
List<Permission> listPermission = userMapper.findPermissionByUsername(username);
for (Permission permission : listPermission) {
authorities.add(new SimpleGrantedAuthority(permission.getPermTag()));
}
// 设置用户权限
user.setAuthorities(authorities);
return user;
}
4)、自定义Security配置案例代码
登入失败处理逻辑:
//认证失败
@Component
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse res, AuthenticationException auth)
throws IOException, ServletException {
System.out.println("登陆失败!");
res.sendRedirect("https://www.zhqwfj.xyz/");
}
}
登入成功处理逻辑
// 认证成功
@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse res, Authentication arg2)
throws IOException, ServletException {
System.out.println("用户认证成功");
res.sendRedirect("/");
}
}
自定义登入密码加密工具类
public class MD5Util {
private static final String SALT = "zhq";
public static String encode(String password) {
password = password + SALT;
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (Exception e) {
throw new RuntimeException(e);
}
char[] charArray = password.toCharArray();
byte[] byteArray = new byte[charArray.length];
for (int i = 0; i < charArray.length; i++)
byteArray[i] = (byte) charArray[i];
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
public static void main(String[] args) {
System.out.println(MD5Util.encode("123456"));
}
}
自定义错误页
@Configuration
public class WebServerAutoConfiguration {
@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
ErrorPage errorPage400 = new ErrorPage(HttpStatus.BAD_REQUEST, "/error/400");
ErrorPage errorPage401 = new ErrorPage(HttpStatus.UNAUTHORIZED, "/error/401");
ErrorPage errorPage403 = new ErrorPage(HttpStatus.FORBIDDEN, "/error/403");
ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND, "/error/404");
ErrorPage errorPage415 = new ErrorPage(HttpStatus.UNSUPPORTED_MEDIA_TYPE, "/error/415");
ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500");
factory.addErrorPages(errorPage400, errorPage401, errorPage403, errorPage404, errorPage415, errorPage500);
return factory;
}
}
用户权限核心配置
@Component
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyAuthenticationFailureHandler failureHandler;
@Autowired
private MyAuthenticationSuccessHandler successHandler;
@Autowired
private MyUserDetailService myUserDetailService;
@Autowired
private PermissionMapper permissionMapper;
/**
* 配置认证用户信息和权限
*
* @param auth 认证
* @throws Exception 异常
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailService).passwordEncoder(new PasswordEncoder() {
/**
* 对表单密码进行加密
* @param charSequence 表单密码
* @return String
*/
@Override
public String encode(CharSequence charSequence) {
return MD5Util.encode((String) charSequence);
}
/**
* 加密的密码和数据库密码做对比
* @param rawPassword 表单密码
* @param encodePassword 数据库密码字段
* @return boolean
*/
@Override
public boolean matches(CharSequence rawPassword, String encodePassword) {
System.out.println("rawPassword:" + rawPassword + ",encodePassword:" + encodePassword);
return MD5Util.encode((String) rawPassword).equals(encodePassword);
}
});
}
/**
* 配置拦截请求资源
*
* @param http 请求
* @throws Exception 异常
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
// 如何权限控制 给每一个请求路径 分配一个权限名称 让后账号只要关联该名称,就可以有访问权限
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry expressionInterceptUrlRegistry = http.authorizeRequests();
//读取数据库权限列表
List<Permission> allPermission = permissionMapper.findAllPermission();
//遍历配置权限
for (Permission permission : allPermission) {
expressionInterceptUrlRegistry.antMatchers(permission.getUrl()).hasAnyAuthority(permission.getPermTag());
}
//允许任何人访问login,设置自定义登入页
expressionInterceptUrlRegistry.antMatchers("/login").permitAll().antMatchers("/**").fullyAuthenticated().and().formLogin().loginPage("/login").
successHandler(successHandler).failureHandler(failureHandler)
.and().csrf().disable();
}
}
5)、测试代码
前端测试页案例代码
@Controller
public class ErrorController {
// 403权限不足页面
@RequestMapping("/error/403")
public String error() {
return "/error/403";
}
...
}
@Controller
public class OrderController {
// 首页
@RequestMapping("/")
public String index() {
return "index";
}
// 查询订单
@RequestMapping("/showOrder")
public String showOrder() {
return "showOrder";
}
// 添加订单
@RequestMapping("/addOrder")
public String addOrder() {
return "addOrder";
}
// 修改订单
@RequestMapping("/updateOrder")
public String updateOrder() {
return "updateOrder";
}
// 删除订单
@RequestMapping("/deleteOrder")
public String deleteOrder() {
return "deleteOrder";
}
// 自定义登陆页面
@GetMapping("/login")
public String login() {
return "login";
}
}
四、测试结果





1009

被折叠的 条评论
为什么被折叠?



