日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

springBoot+springSecurity 数据库动态管理用户、角色、权限(二)

發布時間:2025/3/21 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 springBoot+springSecurity 数据库动态管理用户、角色、权限(二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

序:?
本文使用springboot+mybatis+SpringSecurity 實現數據庫動態的管理用戶、角色、權限管理

本文細分角色和權限,并將用戶、角色、權限和資源均采用數據庫存儲,并且自定義濾器,代替原有的FilterSecurityInterceptor過濾器,?
并分別實現AccessDecisionManager、InvocationSecurityMetadataSourceService和UserDetailsService,并在配置文件中進行相應配置。

spring security的簡單原理:

使用眾多的攔截器對url攔截,以此來管理權限。但是這么多攔截器,筆者不可能對其一一來講,主要講里面核心流程的兩個。

首先,權限管理離不開登陸驗證的,所以登陸驗證攔截器AuthenticationProcessingFilter要講;?
還有就是對訪問的資源管理吧,所以資源管理攔截器AbstractSecurityInterceptor要講;

但攔截器里面的實現需要一些組件來實現,所以就有了AuthenticationManager、accessDecisionManager等組件來支撐。

現在先大概過一遍整個流程,用戶登陸,會被AuthenticationProcessingFilter攔截,調用AuthenticationManager的實現,而且AuthenticationManager會調用ProviderManager來獲取用戶驗證信息(不同的Provider調用的服務不同,因為這些信息可以是在數據庫上,可以是在LDAP服務器上,可以是xml配置文件上等),如果驗證通過后會將用戶的權限信息封裝一個User放到spring的全局緩存SecurityContextHolder中,以備后面訪問資源時使用。?
訪問資源(即授權管理),訪問url時,會通過AbstractSecurityInterceptor攔截器攔截,其中會調用FilterInvocationSecurityMetadataSource的方法來獲取被攔截url所需的全部權限,在調用授權管理器AccessDecisionManager,這個授權管理器會通過spring的全局緩存SecurityContextHolder獲取用戶的權限信息,還會獲取被攔截的url和被攔截url所需的全部權限,然后根據所配的策略(有:一票決定,一票否定,少數服從多數等),如果權限足夠,則返回,權限不夠則報錯并調用權限不足頁面。


重要

本文設計和代碼是基于 上一篇博客(請點擊)

springboot+mybatis+SpringSecurity 實現用戶角色數據庫管理

進行修改。


本文目錄:?
1:數據庫表設計?
2:權限表的業務?
3:springSecurity 配置修改?
4:修改home.html 文件?
5:修改HomeController.Java?文件?
6:測試檢驗

目錄結構如下:


1:數據庫表設計

由于本文增加了權限表所以本文的數據庫表為5個分別是: 用戶表、角色表、權限表、用戶角色中間表、角色權限中間表

初始化數據

注意:Sys_permission 表的url通配符為兩顆星,比如說 /user下的所有url,應該寫成 /user/**;權限的名字可以隨意起名 insert into SYS_USER (id,username, password) values (1,'admin', 'admin'); insert into SYS_USER (id,username, password) values (2,'abel', 'abel');insert into SYS_ROLE(id,name) values(1,'ROLE_ADMIN'); insert into SYS_ROLE(id,name) values(2,'ROLE_USER');insert into SYS_ROLE_USER(SYS_USER_ID,ROLES_ID) values(1,1); insert into SYS_ROLE_USER(SYS_USER_ID,ROLES_ID) values(2,2);BEGIN; INSERT INTO `Sys_permission` VALUES ('1', 'ROLE_HOME', 'home', '/', null), ('2', 'ROLE_ADMIN', 'ABel', '/admin', null); COMMIT;BEGIN; INSERT INTO `Sys_permission_role` VALUES ('1', '1', '1'), ('2', '1', '2'), ('3', '2', '1'); COMMIT;
  • ?

2:權限表的業務代碼

2.1 java bean

2.2 dao 層

在 com.us.example.dao 包下新建PermissionDao.java 文件。

PermissionDao.java

package com.us.example.dao; import com.us.example.config.MyBatisRepository; import com.us.example.domain.Permission; import java.util.List;/*** Created by yangyibo on 17/1/20.*/ public interface PermissionDao {public List<Permission> findAll();public List<Permission> findByAdminUserId(int userId); }

?

在src/resource/mapper目錄下新建對應的mapper.xml 文件

PermissionDaoMapper.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.us.example.dao.PermissionDao"> <select id="findAll" resultType="com.us.example.domain.Permission">SELECT * from Sys_permission ; </select><select id="findByAdminUserId" parameterType="int" resultType="com.us.example.domain.Permission">select p.*from Sys_User uLEFT JOIN sys_role_user sru on u.id= sru.Sys_User_idLEFT JOIN Sys_Role r on sru.Sys_Role_id=r.idLEFT JOIN Sys_permission_role spr on spr.role_id=r.idLEFT JOIN Sys_permission p on p.id =spr.permission_idwhere u.id=#{userId}</select></mapper>

?

3:springSecurity 配置修改

3.1 修改 WebSecurityConfig.java

修改com.us.example.config包下的 WebSecurityConfig.java 文件如下:

package com.us.example.config;import com.us.example.service.CustomUserService; import com.us.example.service.MyFilterSecurityInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;/*** Created by yangyibo on 17/1/18.*/@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate MyFilterSecurityInterceptor myFilterSecurityInterceptor;@BeanUserDetailsService customUserService(){ //注冊UserDetailsService 的beanreturn new CustomUserService();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(customUserService()); //user Details Service驗證}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated() //任何請求,登錄后可以訪問.and().formLogin().loginPage("/login").failureUrl("/login?error").permitAll() //登錄頁面用戶任意訪問.and().logout().permitAll(); //注銷行為任意訪問http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class);} }

?

3.2 修改CustomUserService

修改CustomUserService.java 內容如下:

package com.us.example.service;import com.us.example.dao.PermissionDao; import com.us.example.dao.UserDao; import com.us.example.domain.Permission; import com.us.example.domain.SysRole; import com.us.example.domain.SysUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; 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.ArrayList; import java.util.List;/*** Created by yangyibo on 17/1/18.*/ @Service public class CustomUserService implements UserDetailsService { //自定義UserDetailsService 接口@AutowiredUserDao userDao;@AutowiredPermissionDao permissionDao;public UserDetails loadUserByUsername(String username) {SysUser user = userDao.findByUserName(username);if (user != null) {List<Permission> permissions = permissionDao.findByAdminUserId(user.getId());List<GrantedAuthority> grantedAuthorities = new ArrayList <>();for (Permission permission : permissions) {if (permission != null && permission.getName()!=null) {GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getName());//1:此處將權限信息添加到 GrantedAuthority 對象中,在后面進行全權限驗證時會使用GrantedAuthority 對象。grantedAuthorities.add(grantedAuthority);}}return new User(user.getUsername(), user.getPassword(), grantedAuthorities);} else {throw new UsernameNotFoundException("admin: " + username + " do not exist!");}}}

?

3.3 新增MyAccessDecisionManager

在com.us.example.service 包下新增?
MyAccessDecisionManager.java 文件

package com.us.example.service;import org.springframework.security.access.AccessDecisionManager; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.stereotype.Service;import java.util.Collection; import java.util.Iterator;/*** Created by yangyibo on 17/1/19.*/ @Service public class MyAccessDecisionManager implements AccessDecisionManager {// decide 方法是判定是否擁有權限的決策方法,//authentication 是釋CustomUserService中循環添加到 GrantedAuthority 對象中的權限信息集合.//object 包含客戶端發起的請求的requset信息,可轉換為 HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();//configAttributes 為MyInvocationSecurityMetadataSource的getAttributes(Object object)這個方法返回的結果,此方法是為了判定用戶請求的url 是否在權限表中,如果在權限表中,則返回給 decide 方法,用來判定用戶是否有此權限。如果不在權限表中則放行。@Overridepublic void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {if(null== configAttributes || configAttributes.size() <=0) {return;}ConfigAttribute c;String needRole;for(Iterator<ConfigAttribute> iter = configAttributes.iterator(); iter.hasNext(); ) {c = iter.next();needRole = c.getAttribute();for(GrantedAuthority ga : authentication.getAuthorities()) {//authentication 為在注釋1 中循環添加到 GrantedAuthority 對象中的權限信息集合if(needRole.trim().equals(ga.getAuthority())) {return;}}}throw new AccessDeniedException("no right");}@Overridepublic boolean supports(ConfigAttribute attribute) {return true;}@Overridepublic boolean supports(Class<?> clazz) {return true;} }

?

3.4 新增 MyFilterSecurityInterceptor

在com.us.example.service 包下新增?
MyFilterSecurityInterceptor.java 文件

package com.us.example.service; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.SecurityMetadataSource; import org.springframework.security.access.intercept.AbstractSecurityInterceptor; import org.springframework.security.access.intercept.InterceptorStatusToken; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; import org.springframework.stereotype.Service;import java.io.IOException;/*** Created by yangyibo on 17/1/19.*/ @Service public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {@Autowiredprivate FilterInvocationSecurityMetadataSource securityMetadataSource;@Autowiredpublic void setMyAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager) {super.setAccessDecisionManager(myAccessDecisionManager);}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {FilterInvocation fi = new FilterInvocation(request, response, chain);invoke(fi);}public void invoke(FilterInvocation fi) throws IOException, ServletException { //fi里面有一個被攔截的url //里面調用MyInvocationSecurityMetadataSource的getAttributes(Object object)這個方法獲取fi對應的所有權限 //再調用MyAccessDecisionManager的decide方法來校驗用戶的權限是否足夠InterceptorStatusToken token = super.beforeInvocation(fi);try { //執行下一個攔截器fi.getChain().doFilter(fi.getRequest(), fi.getResponse());} finally {super.afterInvocation(token, null);}}@Overridepublic void destroy() {}@Overridepublic Class<?> getSecureObjectClass() {return FilterInvocation.class;}@Overridepublic SecurityMetadataSource obtainSecurityMetadataSource() {return this.securityMetadataSource;} }

?

3.5 新增 MyInvocationSecurityMetadataSourceService

在com.us.example.service 包下新增MyInvocationSecurityMetadataSourceService.java文件

package com.us.example.service;import com.us.example.dao.PermissionDao; import com.us.example.domain.Permission; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.stereotype.Service;import javax.servlet.http.HttpServletRequest; import java.util.*;/*** Created by yangyibo on 17/1/19.*/ @Service public class MyInvocationSecurityMetadataSourceService implementsFilterInvocationSecurityMetadataSource {@Autowiredprivate PermissionDao permissionDao;private HashMap<String, Collection<ConfigAttribute>> map =null;/*** 加載權限表中所有權限*/public void loadResourceDefine(){map = new HashMap<>();Collection<ConfigAttribute> array;ConfigAttribute cfg;List<Permission> permissions = permissionDao.findAll();for(Permission permission : permissions) {array = new ArrayList<>();cfg = new SecurityConfig(permission.getName());//此處只添加了用戶的名字,其實還可以添加更多權限的信息,例如請求方法到ConfigAttribute的集合中去。此處添加的信息將會作為MyAccessDecisionManager類的decide的第三個參數。array.add(cfg);//用權限的getUrl() 作為map的key,用ConfigAttribute的集合作為 value,map.put(permission.getUrl(), array);}}//此方法是為了判定用戶請求的url 是否在權限表中,如果在權限表中,則返回給 decide 方法,用來判定用戶是否有此權限。如果不在權限表中則放行。@Overridepublic Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {if(map ==null) loadResourceDefine();//object 中包含用戶請求的request 信息HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();AntPathRequestMatcher matcher;String resUrl;for(Iterator<String> iter = map.keySet().iterator(); iter.hasNext(); ) {resUrl = iter.next();matcher = new AntPathRequestMatcher(resUrl);if(matcher.matches(request)) {return map.get(resUrl);}}return null;}@Overridepublic Collection<ConfigAttribute> getAllConfigAttributes() {return null;}@Overridepublic boolean supports(Class<?> clazz) {return true;} }

?

4:修改home.html 文件

修改src/resources/templates目錄下 的home.html

<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"> <head> <meta content="text/html;charset=UTF-8"/> <title sec:authentication="name"></title> <link rel="stylesheet" th:href="@{css/bootstrap.min.css}" /> <style type="text/css"> body {padding-top: 50px; } .starter-template {padding: 40px 15px;text-align: center; } </style> </head> <body><nav class="navbar navbar-inverse navbar-fixed-top"><div class="container"><div class="navbar-header"><a class="navbar-brand" href="#">Spring Security演示</a></div><div id="navbar" class="collapse navbar-collapse"><ul class="nav navbar-nav"><li><a th:href="@{/}"> 首頁 </a></li><li><a th:href="@{/admin}"> admin </a></li></ul></div><!--/.nav-collapse --></div></nav><div class="container"><div class="starter-template"><h1 th:text="${msg.title}"></h1><p class="bg-primary" th:text="${msg.content}"></p><div sec:authorize="hasRole('ROLE_HOME')"> <!-- 用戶類型為ROLE_ADMIN 顯示 --><p class="bg-info" th:text="${msg.etraInfo}"></p></div><div sec:authorize="hasRole('ROLE_ADMIN')"> <!-- 用戶類型為ROLE_ADMIN 顯示 --><p class="bg-info">恭喜您,您有 ROLE_ADMIN 權限 </p></div><form th:action="@{/logout}" method="post"><input type="submit" class="btn btn-primary" value="注銷"/></form></div></div></body> </html>

?

5:修改HomeController.java 文件

package com.us.example.controller;import com.us.example.domain.Msg; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;/*** Created by yangyibo on 17/1/18.*/ @Controller public class HomeController {@RequestMapping("/")public String index(Model model){Msg msg = new Msg("測試標題","測試內容","歡迎來到HOME頁面,您擁有 ROLE_HOME 權限");model.addAttribute("msg", msg);return "home";}@RequestMapping("/admin")@ResponseBodypublic String hello(){return "hello admin";} }

?

6.測試檢驗

啟動訪問?http://localhost:8080/?到登錄頁面

由于數據庫的配置 admin 用戶擁有 訪問 home和admin 頁面的權限。 abel 用戶只有訪問 home 的權限

使用admin 登錄

點擊 admin 按鈕 會反回結果 “hello admin“

使用abel 用戶登錄 點擊 點擊 admin 按鈕 頁面會報403

源碼地址:https://github.com/527515025/springBoot

參考資料:?
http://www.tuicool.com/articles/jq6fuur#c-23220?
http://blog.csdn.net/u012367513/article/details/38866465

總結

以上是生活随笔為你收集整理的springBoot+springSecurity 数据库动态管理用户、角色、权限(二)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。