当前位置:   article > 正文

express mysql 做rbac_spring boot:spring security用mysql数据库实现RBAC权限管理(spring boot 2.3.1)...

mysql搭建rbac教程

一,用数据库实现权限管理要注意哪些环节?

1,需要生成spring security中user类的派生类,用来保存用户id和昵称等信息,

避免页面上显示用户昵称时需要查数据库

2,如果需要在页面上显示用户的登录信息,

需要自定义一个interceptor,

把用户的昵称等信息添加到 modelandview

3,普通用户的角色,即默认的权限,因为每个用户都具有,

就不要写入到数据表中,

避免数据量大时查询缓慢

说明:作者:刘宏缔 邮箱: 371125307@qq.com

二,演示项目的相关信息

1,项目地址:

https://github.com/liuhongdi/securitylogin

2,项目功能说明

演示了使用数据库实现的用户RBAC权限管理

三种页面:

无权限限制页面:任何人都可访问

需登录页面:修改密码等:登录才可以访问

有权限限制页面:必须授予相应的角色后才能访问

3,项目结构:如图:

e83be673bc3e8ea0ad1e432446dd4f55.png

6ef2a53ca2e53b65a648d5cd4fddd5ca.png

d61febded98fbbc7121538d8def2fe5e.png

三,配置文件说明

1,pom.xml

org.springframework.boot

spring-boot-starter-security

org.springframework.boot

spring-boot-starter-thymeleaf

org.springframework.boot

spring-boot-starter-validation

org.mybatis.spring.boot

mybatis-spring-boot-starter

2.1.3

mysql

mysql-connector-java

runtime

com.alibaba

fastjson

1.2.72

2,application.properties

#thymeleaf

spring.thymeleaf.cache=falsespring.thymeleaf.encoding=UTF-8spring.thymeleaf.mode=HTML

spring.thymeleaf.prefix=classpath:/templates/spring.thymeleaf.suffix=.html

#mysql

spring.datasource.url=jdbc:mysql://localhost:3306/security?characterEncoding=utf8&useSSL=false

spring.datasource.username=root

spring.datasource.password=lhddemo

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

#mybatis

mybatis.mapper-locations=classpath:/mapper/*Mapper.xml

mybatis.type-aliases-package=com.example.demo.mapper

#error

server.error.include-stacktrace=always

#log

logging.level.org.springframework.web=trace

3,数据库:

cc1424de3b5bf019557b86a714976540.png

表结构:

CREATE TABLE`sys_user` (

`userId`int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',

`userName`varchar(100) NOT NULL DEFAULT '' COMMENT '用户名',

`password`varchar(100) NOT NULL DEFAULT '' COMMENT '密码',

`nickName`varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '昵称',PRIMARY KEY(`userId`),UNIQUE KEY`userName` (`userName`)

) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户表'

添加数据 :

INSERT INTO `sys_user` (`userId`, `userName`, `password`, `nickName`) VALUES(1, 'lhd', '$2a$10$yGcOz3ekNI6Ya67tqQueS.raxyTOedGsv5jh2BwtRrI5/K9QEIPGq', '老刘'),

(2, 'admin', '$2a$10$yGcOz3ekNI6Ya67tqQueS.raxyTOedGsv5jh2BwtRrI5/K9QEIPGq', '管理员'),

(3, 'merchant', '$2a$10$yGcOz3ekNI6Ya67tqQueS.raxyTOedGsv5jh2BwtRrI5/K9QEIPGq', '商户老张');

说明:3个密码都是111111,仅供演示使用,大家在生产环境中一定不要这样设置

CREATE TABLE`sys_user_role` (

`urId`int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',

`userId`int(11) NOT NULL DEFAULT '0' COMMENT '用户id',

`roleName`varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '角色id',PRIMARY KEY(`urId`),UNIQUE KEY`userId` (`userId`,`roleName`)

) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户角色关联表'

插入数据:

INSERT INTO `sys_user_role` (`urId`, `userId`, `roleName`) VALUES(1, 2, 'ADMIN'),

(2, 3, 'MERCHANT');

四,java代码说明

1,WebSecurityConfig.java

@Configuration

@EnableWebSecuritypublic class WebSecurityConfig extendsWebSecurityConfigurerAdapter {private final static BCryptPasswordEncoder ENCODER = newBCryptPasswordEncoder();

@Resourceprivate UserLoginFailureHandler userLoginFailureHandler;//登录失败的处理类

@Resourceprivate UserLoginSuccessHandler userLoginSuccessHandler;//登录成功的处理类

@Resourceprivate UserLogoutSuccessHandler userLogoutSuccessHandler;//退出成功的处理类

@Resourceprivate UserAccessDeniedHandler userAccessDeniedHandler;//无权访问的处理类

@Resourceprivate SecUserDetailService secUserDetailService; //用户信息类,用来得到UserDetails//指定加密的方式,避免出现:There is no PasswordEncoder mapped for the id "null"

@Beanpublic PasswordEncoder passwordEncoder(){//密码加密类

return newBCryptPasswordEncoder();

}

@Overrideprotected void configure(HttpSecurity http) throwsException {//static

http.authorizeRequests()

.antMatchers("/css/**","/js/**","/img/**")//静态资源等不需要验证

.permitAll();//permitall

http.authorizeRequests()

.antMatchers("/home/**")//permitall

.permitAll();//login

http.formLogin()

.loginPage("/login/login")

.loginProcessingUrl("/login/logined")//发送Ajax请求的路径

.usernameParameter("username")//请求验证参数

.passwordParameter("password")//请求验证参数

.failureHandler(userLoginFailureHandler)//验证失败处理

.successHandler(userLoginSuccessHandler)//验证成功处理

.permitAll(); //登录页面用户任意访问//logout

http.logout()

.logoutUrl("/login/logout")

.logoutSuccessUrl("/login/logout")

.logoutSuccessHandler(userLogoutSuccessHandler)//登出处理

.deleteCookies("JSESSIONID")

.clearAuthentication(true)

.invalidateHttpSession(true)

.permitAll();//有角色的用户才能访问

http.authorizeRequests()

.antMatchers("/admin/**").hasRole("ADMIN")

.antMatchers("/merchant/**").hasAnyRole("MERCHANT","ADMIN");//其他任何请求,登录后可以访问

http.authorizeRequests().anyRequest().authenticated();//accessdenied

http.exceptionHandling().accessDeniedHandler(userAccessDeniedHandler);//无权限时的处理//user detail

http.userDetailsService(secUserDetailService);//rememberme//图形验证码//http.csrf().disable();

}

@Resourcepublic void configureGlobal(AuthenticationManagerBuilder auth) throwsException {

auth.userDetailsService(secUserDetailService).passwordEncoder(newPasswordEncoder() {

@OverridepublicString encode(CharSequence charSequence) {returnENCODER.encode(charSequence);

}//密码匹配,看输入的密码经过加密与数据库中存放的是否一样

@Overridepublic booleanmatches(CharSequence charSequence, String s) {returnENCODER.matches(charSequence,s);

}

});

}

}

2,SecUser.java

public class SecUser extendsUser {//用户id

private intuserid;//用户昵称

privateString nickname;public SecUser(String username, String password, Collection extends GrantedAuthority>authorities) {super(username, password, authorities);

}public SecUser(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection extends GrantedAuthority>authorities) {super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);

}publicString getNickname() {returnnickname;

}public voidsetNickname(String nickname) {this.nickname =nickname;

}public intgetUserid() {returnuserid;

}public void setUserid(intuserid) {this.userid =userid;

}

}

spring security中User类的子类,增加了用户id和昵称,

需要保存到session中的信息,在这里扩展

目的是避免在每个页面上显示用户信息需要查数据库

3,SecUserDetailService.java

/*** Created by liuhongdi on 2020/07/09.*/@Component("SecUserDetailService")public class SecUserDetailService implementsUserDetailsService{

@ResourceprivateSysUserService sysUserService;

@Overridepublic UserDetails loadUserByUsername(String s) throwsUsernameNotFoundException {//查库

SysUser oneUser = sysUserService.getOneUserByUsername(s);//数据库查询 看用户是否存在

String encodedPassword =oneUser.getPassword();

Collection collection = new ArrayList<>();//权限集合//用户权限:需要加 ROLE_

List roles =oneUser.getRoles();//System.out.println(roles);

for(String roleone : roles) {

GrantedAuthority grantedAuthority= new SimpleGrantedAuthority("ROLE_"+roleone);

collection.add(grantedAuthority);

}//增加用户的userid,nickname

SecUser user = newSecUser(s,encodedPassword,collection);

user.setUserid(oneUser.getUserId());

user.setNickname(oneUser.getNickName());returnuser;

}

}

4,UserAccessDeniedHandler.java

@Component("UserAccessDeniedHandler")public class UserAccessDeniedHandler implementsAccessDeniedHandler {

@Overridepublic voidhandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,

AccessDeniedException e)throwsIOException, ServletException {boolean isAjax =ServletUtil.isAjax();//System.out.println("isajax:"+isAjax);

if (isAjax == true) {

ServletUtil.printRestResult(RestResult.error(ResponseCode.ACCESS_DENIED));

}else{

ServletUtil.printString(ResponseCode.ACCESS_DENIED.getMsg());

}

}

}

5,UserLoginFailureHandler.java

@Component("UserLoginFailureHandler")public class UserLoginFailureHandler extendsSimpleUrlAuthenticationFailureHandler {

@Overridepublic voidonAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,

AuthenticationException exception)throwsIOException, ServletException {//System.out.println("UserLoginFailureHandler");

ServletUtil.printRestResult(RestResult.error(ResponseCode.LOGIN_FAIL));

}

}

6,UserLoginSuccessHandler.java

@Component("UserLoginSuccessHandler")public class UserLoginSuccessHandler extendsSimpleUrlAuthenticationSuccessHandler {

@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throwsIOException, ServletException {//System.out.println("UserLoginSuccessHandler");

ServletUtil.printRestResult(RestResult.success(0,"登录成功"));

}

}

7,UserLogoutSuccessHandler.java

@Component("UserLogoutSuccessHandler")public class UserLogoutSuccessHandler implementsLogoutSuccessHandler{

@Overridepublic void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throwsIOException, ServletException {

httpServletRequest.getSession().invalidate();

ServletUtil.printRestResult(RestResult.success(0,"退出成功"));

}

}

8,WebInterceptor.java

@Componentpublic class WebInterceptor extendsHandlerInterceptorAdapter {//如果view不为空,把登录信息传递给模板

@Overridepublic voidpostHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {if (modelAndView != null) {

ModelMap modelMap=modelAndView.getModelMap();

SecUser currentUser=SessionUtil.getCurrentUser();if (currentUser != null) {

modelMap.addAttribute("is_login","1");

modelMap.addAttribute("login_username",currentUser.getNickname());

}else{

modelMap.addAttribute("is_login","0");

modelMap.addAttribute("login_username","");

}

}

}

}

负责把传递页面公共部分显示的数据到模板

9,login.html

登录页面

body{padding-top:50px;

}.starter-template{padding:40px 15px;text-align:center;

}

首页
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/181751
推荐阅读
相关标签
  

闽ICP备14008679号