springsecurity輕松實(shí)現(xiàn)角色權(quán)限的示例代碼
問題:
如何在springboot項(xiàng)目中使用springsecurity去實(shí)現(xiàn)角色權(quán)限管理呢?本文將盡可能簡單的一步步實(shí)現(xiàn)對接口的角色權(quán)限管理。
項(xiàng)目框架:
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:
實(shí)體類User要實(shí)現(xiàn)springsecurity的基本接口UserDetails,UserDetails里繼承了Serializable,不用擔(dān)心序列化
@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; } }
實(shí)體類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{ 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" propert="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:
首先實(shí)現(xiàn)UserDetailsService類。自定義獲取用戶信息和角色信息。
@Component public class CustomUserDetailsService implements UserDetailsService { @Autowired private UserService userService; @Autowired private HttpServletRequest request; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 通過用戶名從數(shù)據(jù)庫獲取用戶信息 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_`開頭,數(shù)據(jù)庫中沒有,則在這里加 authorities.add(new SimpleGrantedAuthority("ROLE_" + role)); return new User( user.getUsername(), user.getPassword(), authorities ); } }
自定義錯(cuò)誤提示
@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':'沒有訪問權(quán)限'}"); 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("用戶擁有規(guī)定角色才允許訪問的路徑,如:'/user/delte'").hasRole("admin") .antMatchers("規(guī)定ip才允許訪問的路徑,如:'/*'").hasIpAddress("192.168.1.1/24"); .anyRequest().authenticated() // 所有請求都需要驗(yàn)證 .and() // 跳轉(zhuǎn)自定義成功頁 .formLogin().defaultSuccessUrl("/html/index.html") .and() .exceptionHandling() //用戶無權(quán)限訪問鏈接,給出友好提示 .accessDeniedHandler(accessDeniedHandler) .and() .csrf().disable();// post請求要關(guān)閉csrf驗(yàn)證,不然訪問報(bào)錯(cuò);實(shí)際開發(fā)中要開啟。 } }
至此,springsecurity的角色權(quán)限管理就完成了,如果想要實(shí)現(xiàn)方法級的角色權(quán)限限制,可以在方法前加入 @PreAuthorize("hasRole('角色')")注解,多個(gè)角色可以使用hasAnyRole(),就可以限制擁有規(guī)定角色權(quán)限的用戶才能訪問了。
@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("刪除失敗"); }
到此這篇關(guān)于springsecurity輕松實(shí)現(xiàn)角色權(quán)限的示例代碼的文章就介紹到這了,更多相關(guān)springsecurity 角色權(quán)限內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Idea安裝Eslint插件提示:Plugin NativeScript was not installed的問題
這篇文章主要介紹了Idea安裝Eslint插件提示:Plugin NativeScript was not installed的問題,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10springcloud使用feign調(diào)用服務(wù)時(shí)參數(shù)內(nèi)容過大問題
這篇文章主要介紹了springcloud使用feign調(diào)用服務(wù)時(shí)參數(shù)內(nèi)容過大問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03SpringBoot中實(shí)現(xiàn)文件上傳、下載、刪除功能的步驟
本文將詳細(xì)介紹如何在 Spring Boot 中實(shí)現(xiàn)文件上傳、下載、刪除功能,采用的技術(shù)框架包括:Spring Boot 2.4.2、Spring MVC、MyBatis 3.5.6、Druid 數(shù)據(jù)源、JUnit 5 等,文中有詳細(xì)的操作步驟和示例代碼供大家參考,需要的朋友可以參考下2024-01-01基于HttpServletRequest 相關(guān)常用方法的應(yīng)用
本篇文章小編為大家介紹,基于HttpServletRequest 相關(guān)常用方法的應(yīng)用,需要的朋友參考下2013-04-04基于SpringMVC攔截器實(shí)現(xiàn)接口耗時(shí)監(jiān)控功能
本文呢主要介紹了基于SpringMVC攔截器實(shí)現(xiàn)的接口耗時(shí)監(jiān)控功能,統(tǒng)計(jì)接口的耗時(shí)情況屬于一個(gè)可以復(fù)用的功能點(diǎn),因此這里直接使用 SpringMVC的HandlerInterceptor攔截器來實(shí)現(xiàn),需要的朋友可以參考下2024-02-02