管理员
2024-11-23 19:02:07
0
权限控制(springboot整合security实现权限控制)
CREATE TABLE `t_sys_user` (`user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',`user_name` varchar(30) NOT NULL COMMENT '用户名',`user_password` varchar(128) NOT NULL COMMENT '用户密码',`salt` varchar(64) DEFAULT NULL COMMENT '加密盐',`user_phone` varchar(20) DEFAULT NULL COMMENT '手机号',`user_emai` varchar(20) DEFAULT NULL COMMENT '邮箱',`user_title` varchar(20) DEFAULT NULL COMMENT '职称',`creater_id` bigint(20) DEFAULT NULL COMMENT '创建人ID',`creater_name` varchar(30) DEFAULT NULL COMMENT '创建人名称',`creater_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`updater_id` bigint(20) DEFAULT NULL COMMENT '更新人ID',`updater_name` varchar(30) DEFAULT NULL COMMENT '更新人名称',`updater_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',`role_ids` varchar(200) DEFAULT NULL,`role_names` varchar(300) DEFAULT NULL, PRIMARY KEY (`user_id`) ) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;
CREATE TABLE `t_sys_user_role` (`user_role_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户角色ID',`user_id` bigint(20) NOT NULL COMMENT '用户ID',`role_id` bigint(20) NOT NULL COMMENT '角色ID', PRIMARY KEY (`user_role_id`) ) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8;
CREATE TABLE `t_sys_role` (`role_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '角色ID',`role_name` varchar(100) NOT NULL COMMENT '角色名称',`role_code` varchar(100) NOT NULL COMMENT '角色编码',`creater_id` bigint(20) DEFAULT NULL COMMENT '创建人ID',`creater_name` varchar(30) DEFAULT NULL COMMENT '创建人名称',`creater_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`updater_id` bigint(20) DEFAULT NULL COMMENT '更新人ID',`updater_name` varchar(30) DEFAULT NULL COMMENT '更新人名称',`updater_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',`permission_ids` varchar(200) DEFAULT NULL,`permission_names` varchar(300) DEFAULT NULL, PRIMARY KEY (`role_id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
CREATE TABLE `t_sys_role_permission` (`role_permission_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '角色权限ID',`role_id` bigint(20) NOT NULL COMMENT '角色ID',`permission_id` bigint(20) NOT NULL COMMENT '权限ID', PRIMARY KEY (`role_permission_id`) ) ENGINE=InnoDB AUTO_INCREMENT=78 DEFAULT CHARSET=utf8;
1.5.权限表
CREATE TABLE `t_sys_permission` (`permission_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '权限ID',`permission_name` varchar(100) NOT NULL COMMENT '权限名称',`permission_code` varchar(100) NOT NULL COMMENT '权限编码',`creater_id` bigint(20) DEFAULT NULL COMMENT '创建人ID',`creater_name` varchar(30) DEFAULT NULL COMMENT '创建人名称',`creater_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`updater_id` bigint(20) DEFAULT NULL COMMENT '更新人ID',`updater_name` varchar(30) DEFAULT NULL COMMENT '更新人名称',`updater_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`permission_id`) ) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;
org.springframework.boot spring-boot-starter-security
package com.lz.hehuorenservice.system.entity;import com.lz.hehuorenservice.common.entity.BaseEntity;import io.swagger.annotations.ApiModelProperty;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.authority.SimpleGrantedAuthority;import org.springframework.security.core.userdetails.UserDetails;import java.util.*;/** Create by hyhweb on 2021/6/6 16:24 */public class User extends BaseEntity implements UserDetails {/** 用户主键ID */@ApiModelProperty(value = "用户主键ID")private Long userId;/** 用户名 */@ApiModelProperty(value = "用户名")private String userName;/** 用户密码 */@ApiModelProperty(value = "用户密码")private String userPassword;@ApiModelProperty(value = "")private String salt;/** 手机号 */@ApiModelProperty(value = "手机号")private String userPhone;/** 邮箱 */@ApiModelProperty(value = "邮箱")private String userEmai;/** 职称 */@ApiModelProperty(value = "职称")private String userTitle;@ApiModelProperty(value = "角色ID")private String roleIds;@ApiModelProperty(value = "角色名称")private String roleNames;/** 创建人ID */@ApiModelProperty(value = "创建人ID")private Long createrId;/** 创建人名称 */@ApiModelProperty(value = "创建人名称")private String createrName;/** 创建时间 */@ApiModelProperty(value = "创建时间")private Date createrTime;/** 更新人ID */@ApiModelProperty(value = "更新人ID")private Long updaterId;/** 更新人名称 */@ApiModelProperty(value = "更新人名称")private String updaterName;/** 更新时间 */@ApiModelProperty(value = "更新时间")private Date updaterTime;private Setpermissions;@Overridepublic Collection extends GrantedAuthority> getAuthorities() { List authorities = new ArrayList<>();/* //绑定角色的授权方法 if(roles !=null){ for (Role sysRole : roles) { authorities.add(new SimpleGrantedAuthority(sysRole.getRoleCode())); } }*/// 绑定权限的授权方法if (permissions != null) {for (String permission : permissions) { authorities.add(new SimpleGrantedAuthority(permission)); } }return authorities; }@Overridepublic String getPassword() {return userPassword; }@Overridepublic String getUsername() {return userName; }@Overridepublic boolean isAccountNonExpired() {return true; }@Overridepublic boolean isAccountNonLocked() {return true; }@Overridepublic boolean isCredentialsNonExpired() {return true; }@Overridepublic boolean isEnabled() {return true; }public Long getUserId() {return userId; }public void setUserId(Long userId) {this.userId = userId; }public String getUserName() {return userName; }public void setUserName(String userName) {this.userName = userName; }public String getUserPassword() {return userPassword; }public void setUserPassword(String userPassword) {this.userPassword = userPassword; }public String getSalt() {return salt; }public void setSalt(String salt) {this.salt = salt; }public String getUserPhone() {return userPhone; }public void setUserPhone(String userPhone) {this.userPhone = userPhone; }public String getUserEmai() {return userEmai; }public void setUserEmai(String userEmai) {this.userEmai = userEmai; }public String getUserTitle() {return userTitle; }public void setUserTitle(String userTitle) {this.userTitle = userTitle; }public String getRoleIds() {return roleIds; }public void setRoleIds(String roleIds) {this.roleIds = roleIds; }public String getRoleNames() {return roleNames; }public void setRoleNames(String roleNames) {this.roleNames = roleNames; }public Long getCreaterId() {return createrId; }public void setCreaterId(Long createrId) {this.createrId = createrId; }public String getCreaterName() {return createrName; }public void setCreaterName(String createrName) {this.createrName = createrName; }public Date getCreaterTime() {return createrTime; }public void setCreaterTime(Date createrTime) {this.createrTime = createrTime; }public Long getUpdaterId() {return updaterId; }public void setUpdaterId(Long updaterId) {this.updaterId = updaterId; }public String getUpdaterName() {return updaterName; }public void setUpdaterName(String updaterName) {this.updaterName = updaterName; }public Date getUpdaterTime() {return updaterTime; }public void setUpdaterTime(Date updaterTime) {this.updaterTime = updaterTime; }public Set getPermissions() {return permissions; }public void setPermissions(Set permissions) {this.permissions = permissions; } }
package com.lz.hehuorenservice.system.service.impl;import com.lz.hehuorenservice.common.service.impl.BaseServiceImpl;import com.lz.hehuorenservice.system.dao.UserDao;import com.lz.hehuorenservice.system.entity.User;import com.lz.hehuorenservice.system.service.UserService;import org.springframework.beans.factory.annotation.Autowired;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.Service;import java.util.Set;/** Create by hyhweb on 2021/6/6 16:28 */@Servicepublic class UserServiceImpl extends BaseServiceImplimplements UserService, UserDetailsService {@Autowired UserDao userDao;@Overridepublic UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { User user = userDao.getUserByName(userName);if (user == null) {throw new UsernameNotFoundException("账户不存在"); } Set permissions = userDao.getPermissionByUserId(user.getUserId()); user.setPermissions(permissions);return user; } }
package com.lz.hehuorenservice.common.config;import com.fasterxml.jackson.databind.ObjectMapper;import com.lz.hehuorenservice.common.bean.CustomAccessDeniedHandler;import com.lz.hehuorenservice.common.bean.CustomAuthenticationEntryPoint;import com.lz.hehuorenservice.common.filter.CustomAuthenticationFilter;import com.lz.hehuorenservice.system.entity.User;import com.lz.hehuorenservice.system.service.impl.UserServiceImpl;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.authentication.*;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.core.Authentication;import org.springframework.security.core.AuthenticationException;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import org.springframework.security.crypto.password.PasswordEncoder;import org.springframework.security.web.access.AccessDeniedHandler;import org.springframework.security.web.authentication.AuthenticationFailureHandler;import org.springframework.security.web.authentication.AuthenticationSuccessHandler;import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;import org.springframework.security.web.authentication.logout.LogoutHandler;import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;import org.springframework.web.cors.CorsUtils;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;import java.util.HashMap;import java.util.Map;/** Create by hyhweb on 2021/6/7 8:26 */@Configuration@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired UserServiceImpl userService; // 这个必须是接口的实现类,不能是接口@BeanPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder(10);// return NoOpPasswordEncoder.getInstance();}/* @Bean RoleHierarchy roleHierarchy() { RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl(); // String hierarchy = "ROLE_dba> ROLE_admin \n ROLE_admin > ROLE_user"; String hierarchy = "ROLE_admin > ROLE_user"; roleHierarchy.setHierarchy(hierarchy); return roleHierarchy; }*/@BeanCustomAuthenticationFilter customAuthenticationFilter() throws Exception {CustomAuthenticationFilter filter = new CustomAuthenticationFilter();filter.setAuthenticationSuccessHandler( new AuthenticationSuccessHandler() { @Overridepublic void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication auth)throws IOException, ServletException {Object principal = auth.getPrincipal(); resp.setContentType("application/json;charset=utf-8");PrintWriter out = resp.getWriter(); resp.setStatus(200);Mapmap = new HashMap<>();map.put("code", "1");map.put("success", true);map.put("message", "登录成功");User user = (User) principal; user.setUserPassword(null);map.put("data", user);ObjectMapper om = new ObjectMapper(); out.write(om.writeValueAsString(map)); out.flush(); out.close();/* resp.setContentType("application/json;charset=utf-8"); PrintWriter out = resp.getWriter(); Map map = new HashMap (); map.put("message", "登录成功"); out.write(new ObjectMapper().writeValueAsString(map)); out.flush(); out.close();*/} });filter.setAuthenticationFailureHandler( new AuthenticationFailureHandler() { @Overridepublic void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException e)throws IOException, ServletException { resp.setContentType("application/json;charset=utf-8");PrintWriter out = resp.getWriter(); resp.setStatus(401);Map map = new HashMap<>();map.put("status", 401);if (e instanceof LockedException) {map.put("msg", "账号被锁定,登录失败"); } else if (e instanceof BadCredentialsException) {map.put("msg", "账号或密码输入错误,请重新登录"); } else if (e instanceof DisabledException) {map.put("msg", "账号被禁用,登录失败"); } else if (e instanceof AccountExpiredException) {map.put("msg", "账号过期,登录失败"); } else if (e instanceof CredentialsExpiredException) {map.put("msg", "密码过期,登录失败"); } else {map.put("msg", "登录失败"); }ObjectMapper om = new ObjectMapper(); out.write(om.writeValueAsString(map)); out.flush(); out.close();/*resp.setContentType("application/json;charset=utf-8"); PrintWriter out = resp.getWriter(); Map map = new HashMap (); map.put("message", "登录失败"); out.write(new ObjectMapper().writeValueAsString(map)); out.flush(); out.close();*/} });filter.setAuthenticationManager(authenticationManagerBean());return filter; } @Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userService); } @Beanpublic AccessDeniedHandler getAccessDeniedHandler() {return new CustomAccessDeniedHandler(); } @Overridepublic void configure(WebSecurity web) throws Exception { web.ignoring() .antMatchers("/sessionInvalid", "/register", "/app/**", "/login_page") .antMatchers("/index.html", "/static/**", "/favicon.ico") .antMatchers("/swagger-ui/**","/swagger/**","/doc.html","/swagger-resources/**","/images/**","/webjars/**","/v3/api-docs","/configuration/ui","/configuration/security"); } @Overrideprotected void configure(HttpSecurity http) throws Exception { http.cors() // 开启跨域.and() // 获取一个安全编译器.authorizeRequests() // 授权请求.requestMatchers(CorsUtils::isPreFlightRequest) .permitAll() // 跨域的请求开放所有权限.anyRequest() // 所有请求.authenticated() // 所有请求都需要认证.and() .sessionManagement() .invalidSessionUrl("/session/invalid") .and()// 获取一个安全编译器.formLogin()// 表单登录配置.loginPage("/login_page")// 登录页面访问地址.loginProcessingUrl("/login")// 配置登录接口地址.usernameParameter("userName")// 配置登录的账号字段.passwordParameter("userPassWord")// 配置登录密码字段.and()// 获取一个安全编译器.logout()// 退出登录配置.logoutUrl("/logout")// 设置退出登录的接口地址.clearAuthentication(true)// 清除所有认证信息.invalidateHttpSession(true)// 让session失效.addLogoutHandler( new LogoutHandler() {// 退出登录时的处理器@Overridepublic void logout(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,Authentication authentication) {} }) .logoutSuccessHandler( new LogoutSuccessHandler() {// 退出成功后的处理器@Overridepublic void onLogoutSuccess(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,Authentication authentication)throws IOException, ServletException { httpServletResponse.setContentType("application/json;charset=utf-8");PrintWriter out = httpServletResponse.getWriter();Map map = new HashMap<>();map.put("message", "退出成功");map.put("code", "1");map.put("success", true);ObjectMapper om = new ObjectMapper(); out.write(om.writeValueAsString(map)); out.flush(); out.close(); } }) .permitAll() // 设置退出登录的所有权限.and() // 获取一个安全编译器.csrf() .disable() // 关闭csrf跨站点请求伪造.exceptionHandling() .authenticationEntryPoint(new CustomAuthenticationEntryPoint());// 自定义认证的入口异常处理方法http.addFilterAt(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); // 重写用户名密码的过滤器,实现前后端分离获取登录的用户名,密码信息http.exceptionHandling().accessDeniedHandler(getAccessDeniedHandler()); // 没有权限访问的处理器 } }
package com.lz.hehuorenservice.common.bean;import com.fasterxml.jackson.databind.ObjectMapper;import org.springframework.security.access.AccessDeniedException;import org.springframework.security.web.access.AccessDeniedHandler;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;import java.util.HashMap;import java.util.Map;/** Create by hyhweb on 2021/6/7 11:50 */public class CustomAccessDeniedHandler implements AccessDeniedHandler { @Overridepublic void handle(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,AccessDeniedException e)throws IOException, ServletException { httpServletResponse.setContentType("application/json;charset=utf-8");PrintWriter out = httpServletResponse.getWriter();Map map = new HashMap<>();map.put("message", "权限不足,请联系管理员开通权限");map.put("code", 0);map.put("status", 403);map.put("success", false);String result = new ObjectMapper().writeValueAsString(map); out.write(result); out.flush(); out.close(); } }
package com.lz.hehuorenservice.common.bean;import com.fasterxml.jackson.databind.ObjectMapper;import org.springframework.security.core.AuthenticationException;import org.springframework.security.web.AuthenticationEntryPoint;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;import java.util.HashMap;import java.util.Map;/** Create by hyhweb on 2021/6/7 11:42 */public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint { @Overridepublic void commence(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,AuthenticationException e)throws IOException, ServletException { httpServletResponse.setContentType("application/json;charset=utf-8");PrintWriter out = httpServletResponse.getWriter();Map map = new HashMap<>();map.put("message", "还没登录,请重新登录");map.put("code", 302);String result = new ObjectMapper().writeValueAsString(map); out.write(result); out.flush(); out.close(); } }
package com.lz.hehuorenservice.common.filter;import org.springframework.http.MediaType;import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;import org.springframework.security.core.Authentication;import org.springframework.security.core.AuthenticationException;import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.InputStream;/** Create by hyhweb on 2021/6/7 12:07 */public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {@Overridepublic Authentication attemptAuthentication( HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {if (request.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE) || request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) { UsernamePasswordAuthenticationToken authRequest = null;try (InputStream is = request.getInputStream()) { ObjectMapper mapper = new ObjectMapper(); MapauthenticationBean = mapper.readValue(is, Map.class); authRequest = new UsernamePasswordAuthenticationToken( authenticationBean.get("userName"), authenticationBean.get("userPassWord"));/* authRequest = new UsernamePasswordAuthenticationToken( request.getParameter("userName"), request.getParameter("userPassWord"));*/} catch (IOException e) { e.printStackTrace(); authRequest = new UsernamePasswordAuthenticationToken("", ""); } finally { setDetails(request, authRequest);return this.getAuthenticationManager().authenticate(authRequest); } } else {return super.attemptAuthentication(request, response); } } }
@RestController@RequestMapping("/user")@Api(tags = "用户信息") public class UserController{@Autowired private UserService userService;@ApiOperation(value = "删除单个对象", notes = "删除单个对象接口")@GetMapping("/delete/{id}")@PreAuthorize("hasAuthority('delete')") public ApiResult deleteById(@PathVariable long id) {return userService.deleteById(id); } }
org.springframework.security.access.expression.SecurityExpressionRoot
在controller的方法中使用注释,如下:
@PreAuthorize("表达式('权限值')")
@PreAuthorize("hasAuthority('zixunguanli-xinzeng')") public ApiResult add(@RequestBody String json) {return infoService.add(JSON.parseObject(json, InfoReq.class)); }
表达式如下:
boolean hasAuthority(String var1);boolean hasAnyAuthority(String... var1);boolean hasRole(String var1);boolean hasAnyRole(String... var1);boolean permitAll();boolean denyAll();boolean isAnonymous();boolean isAuthenticated();boolean isRememberMe();boolean isFullyAuthenticated();boolean hasPermission(Object var1, Object var2);boolean hasPermission(Object var1, String var2, Object var3);
重构
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter的attemptAuthentication方法