转载

springsecurity轻松实现角色权限

问题:

如何在springboot项目中使用springsecurity去实现角色权限管理呢?本文将尽可能简单的一步步实现对接口的角色权限管理。

项目框架:

springsecurity轻松实现角色权限

sql:

user表:

CREATE TABLE `user` (
  `Id` int NOT NULL AUTO_INCREMENT,
  `UserName` varchar(255) NOT NULL,
  `CreatedDT` datetime DEFAULT NULL,
  `Age` int DEFAULT NULL,
  `Gender` int DEFAULT NULL,
  `Password` varchar(255) NOT NULL,
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

role表:

CREATE TABLE `role` (
  `Id` int NOT NULL AUTO_INCREMENT,
  `UserId` int DEFAULT NULL,
  `Role` varchar(255) DEFAULT NULL,
  `CreatedDT` datetime DEFAULT NULL,
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

maven:

在pom.xml中加入

<dependency/>  
 <groupId/>org.projectlombok</groupId/>  
 <artifactId/>lombok</artifactId/>  
 <optional/>true</optional/>  
 </dependency/>  
 <!--SpringSecurity依赖配置-->  
 <dependency/>  
 <groupId/>org.springframework.boot</groupId/>  
 <artifactId/>spring-boot-starter-security</artifactId/>  
 </dependency/>  
 <!--Hutool Java工具包-->  
 <dependency/>  
 <groupId/>cn.hutool</groupId/>  
 <artifactId/>hutool-all</artifactId/>  
 <version/>4.5.7</version/>  
 </dependency/>

model:

实体类User要实现springsecurity的基本接口UserDetails,UserDetails里继承了Serializable,不用担心序列化

@Data  
public class User implements UserDetails {  
​  
 public User() {  
 }  
​  
 private static final long serialVersionUID = 1L;  
   
 private Integer  id;  
​  
 private String  userName;  
​  
 private Date  createdDT;  
​  
 private Integer  age;  
​  
 private Integer  gender;  
​  
 private String passWord;  
​  
 private String role;  
​  
 private List<GrantedAuthority> authorities;  
​  
 public User(String userName, String passWord, List<GrantedAuthority> authorities) {  
 this.userName = userName;  
 this.passWord = passWord;  
 this.authorities = authorities;  
 }  
​  
 @Override  
 public Collection<? extends GrantedAuthority> getAuthorities() {  
 return authorities;  
 }  
​  
 @Override  
 public String getPassword() {  
 return this.passWord;  
 }  
​  
 @Override  
 public String getUsername() {  
 return this.userName;  
 }  
​  
 @Override  
 public boolean isAccountNonExpired() {  
 return true;  
 }  
​  
 @Override  
 public boolean isAccountNonLocked() {  
 return true;  
 }  
​  
 @Override  
 public boolean isCredentialsNonExpired() {  
 return true;  
 }  
​  
 @Override  
 public boolean isEnabled() {  
 return true;  
 }  
}  
​

实体类role:

@Data  
public class Role implements Serializable {  
 private Integer id;  
​  
 private String role;  
​  
 private Date createdDT;  
​  
 private Integer userId;  
}  
​

mapper:

@Mapper  
public interface UserMapper{  
 User selectOneByName(User user);  
}

service:

public interface UserService extends BaseService<User/> {  
 User selectOneByName(User user) throws ServiceException;  
}

serviceImpl:

@Service  
public class UserServiceImpl implements UserService {  
 @Autowired  
 private UserMapper mapper;  
​  
 @Override  
 public User selectOneByName(User user) throws ServiceException {  
 return mapper.selectOneByName(user);  
 }  
}

mapper.xml:

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
<mapper namespace/="com.pzh.hyh.demo.mapper.UserMapper"/><!--    mapper相对路径-->  
 <resultMap id/="BaseResultMap" type/="com.pzh.hyh.demo.model.User"/><!--    model相对路径-->  
 <result column/="Id" jdbcType/="INTEGER" property/="id"/>  
 <result column/="UserName" jdbcType/="VARCHAR" property/="userName"/>  
 <result column/="CreatedDT" jdbcType/="TIMESTAMP" property/="createdDT"/>  
 <result column/="Age" jdbcType/="INTEGER" property/="age"/>  
 <result column/="Gender" jdbcType/="INTEGER" property/="gender"/>  
 <result column/="Password" jdbcType/="VARCHAR" property/="passWord"/>  
 </resultMap/>  
​  
 <sql id/="Base/_Column/_List"/>  
 Id, UserName, CreatedDT, Age, Gender,Password  
 </sql/>  
   
 <select id/="selectOneByName" parameterType/="com.pzh.hyh.demo.model.User" resultMap/="BaseResultMap"/><!--    model相对路径-->  
 SELECT u./*,r.role FROM /`user/` u LEFT JOIN role r on u.Id = r.UserId  
 where u.UserName = #{userName,jdbcType=VARCHAR}  
 </select/>  
​  
</mapper/>

config:

首先实现UserDetailsService类。自定义获取用户信息和角色信息。

@Component  
public class CustomUserDetailsService implements UserDetailsService {  
 @Autowired  
 private UserService userService;  
​  
 @Autowired  
 private HttpServletRequest request;  
​  
 @Override  
 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {  
 // 通过用户名从数据库获取用户信息  
 User user /= userService.selectOneByName(new User(){  
 {  
 setUserName(username);  
 }  
 });  
 if (user /== null) {  
 throw new UsernameNotFoundException("用户不存在");  
 }  
​  
 HttpSession session /= request.getSession();  
 session.setAttribute(session.getId(),user);  
​  
 // 得到用户角色  
 String role /= user.getRole();  
​  
 // 角色集合  
 List<GrantedAuthority/> authorities /= new ArrayList<>();  
 // 角色必须以/`ROLE/_/`开头,数据库中没有,则在这里加  
 authorities.add(new SimpleGrantedAuthority("ROLE/_" + role));  
​  
 return new User(  
 user.getUsername(),  
 user.getPassword(),  
 authorities  
 );  
 }  
}

自定义错误提示

@Component  
public class MyAccessDeniedHandler implements AccessDeniedHandler {  
 @Override  
 public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {  
 response.setCharacterEncoding("UTF-8");  
 response.setContentType("application/json");  
 response.getWriter().println("{'code':'403','message':'没有访问权限'}");  
 response.getWriter().flush();  
 }  
}

终于来到security的配置了

@EnableWebSecurity  
@EnableGlobalMethodSecurity(prePostEnabled /= true)  
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {  
 @Autowired  
 private CustomUserDetailsService userDatailService;  
​  
 @Autowired  
 private MyAccessDeniedHandler accessDeniedHandler;  
​  
 @Bean  
 public PasswordEncoder passwordEncoder(){  
 return new BCryptPasswordEncoder();  
 }  
​  
 @Override  
 protected void configure(AuthenticationManagerBuilder auth) throws Exception {  
 auth  
 .userDetailsService(userDatailService)  
 .passwordEncoder(passwordEncoder());  
 }  
​  
​  
 @Override  
 protected void configure(HttpSecurity http) throws Exception {  
 http  
 .headers().frameOptions().disable()  
 .and()  
 .authorizeRequests()  
 .antMatchers("不限制访问的路径,如:'/user//*'").permitAll()  
 .antMatchers("用户拥有规定角色才允许访问的路径,如:'/user/delte'").hasRole("admin")  
 .antMatchers("规定ip才允许访问的路径,如:'//*'").hasIpAddress("192.168.1.1/24");  
 .anyRequest().authenticated() // 所有请求都需要验证  
 .and()  
 // 跳转自定义成功页  
 .formLogin().defaultSuccessUrl("/html/index.html")  
 .and()  
 .exceptionHandling()  
 //用户无权限访问链接,给出友好提示  
 .accessDeniedHandler(accessDeniedHandler)  
 .and()  
 .csrf().disable();// post请求要关闭csrf验证,不然访问报错;实际开发中要开启。  
 }  
}

至此,springsecurity的角色权限管理就完成了,如果想要实现方法级的角色权限限制,可以在方法前加入 @PreAuthorize("hasRole('角色')")注解,多个角色可以使用hasAnyRole(),就可以限制拥有规定角色权限的用户才能访问了。

@PreAuthorize("hasRole('admin')")  
 @RequestMapping(value /= "/delete")  
 public CommonResult delete(@RequestBody int id) {  
 int i /= userService.delete(new User() {  
 {  
 setId(id);  
 }  
 });  
 return i /> 0 ? processSuccess("删除成功") : processFailure("删除失败");  
 }
原文  https://segmentfault.com/a/1190000022146135
正文到此结束
Loading...