Spring Boot 동적 권한 변경 문제 에 대한 실현 방안
웹 프로젝트 에서 권한 관리 즉 권한 액세스 제 어 는 사이트 액세스 안전 에 보장 을 제공 하고 많은 프로젝트 가 Session 을 캐 시 로 사용 하여 AOP 기술 과 결합 하여 token 인증 과 권한 제 어 를 한다.권한 제어 프로 세 스 는 다음 그림 과 같 습 니 다.
현재 관리자 가 사용자 의 역할 을 수정 하거나 캐릭터 의 권한 을 수정 하면 사용자 권한 에 변화 가 생 길 수 있 습 니 다.이때 동적 권한 변경 을 어떻게 실현 하여 전단 이 사용자 의 권한 트 리 를 업데이트 할 수 있 고 백 엔 드 액세스 권한 AOP 모듈 은 이러한 변경 사항 을 알 수 있 습 니까?
2.문제 및 해결 방안
현재 문 제 는 관리자 가 사용자 세 션 에 접근 할 수 없 기 때문에 변경 사항 을 사용자 에 게 알 릴 수 없습니다.사용자 가 로그 인 을 했 거나 로그 인 동작 이 아 닌 브 라 우 저 페이지 를 직접 닫 으 면 Session 이 만 료 되 기 전,사용자 가 인터페이스 에 접근 할 때 액세스 권한 AOP 모듈 은 여전히 이전 캐 시 된 Session 정보 에 따라 처리 되 므 로 동적 권한 변경 이 불가능 합 니 다.
*8195:8195:Security+WebSocket 을 사용 하 는 것 은 하나의 방안 이지 만 온라인 사용 자 를 처리 할 수 없습니다.
솔 루 션 의 핵심 사상 은 ServletContext 대상 의 공유 특성 을 이용 하여 사용자 권한 이 변 경 된 정보 전달 을 실현 하 는 것 이다.그리고 AOP 클래스 에서 사용자 가 변경 알림 기록 을 처리 해 야 하 는 지,권한 이 변경 되면 response 메시지 체 를 수정 하고 전단 에 추가 알림 정 보 를 추가 합 니 다.전단 에 추가 알림 정 보 를 받 으 면 기능 권한 트 리 를 업데이트 하고 관련 처 리 를 할 수 있 습 니 다.
이렇게 이용 한 변경 알림 서 비 스 는 백 엔 드 의 사용자 url 방문 인터페이스 가 최초 로 변경 을 알 수 있 을 뿐만 아니 라 전단 에 도 알려 동적 권한 변경 을 실현 할 수 있 습 니 다.
3.방안 실현
3.1 개발 변경 알림 유형
서비스 인터페이스 류 ChangeNotify Service,코드 는 다음 과 같 습 니 다.
package com.abc.questInvest.service;
/**
* @className : ChangeNotifyService
* @description :
* @summary :
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/06/28 1.0.0 sheng.zheng
*
*/
public interface ChangeNotifyService {
/**
*
* @methodName : getChangeNotifyInfo
* @description : ID
* @param userId : ID
* @return : 0 , bitmap 。 :
* bit0: : , ;
* bit1: : , ;
* bit2: : , ;
* bit3: : , ;
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/06/28 1.0.0 sheng.zheng
*
*/
public Integer getChangeNotifyInfo(Integer userId);
/**
*
* @methodName : setChangeNotifyInfo
* @description :
* @param userId : ID
* @param changeNotifyInfo :
* bit0: : , ;
* bit1: : , ;
* bit2: : , ;
* bit3: : , ;
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/06/28 1.0.0 sheng.zheng
*
*/
public void setChangeNotifyInfo(Integer userId,Integer changeNotifyInfo);
}
서비스 실현 류 Change Notify ServiceImpl,코드 는 다음 과 같 습 니 다.
package com.abc.questInvest.service.impl;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Service;
import com.abc.questInvest.service.ChangeNotifyService;
/**
* @className : ChangeNotifyServiceImpl
* @description : ChangeNotifyService
* @summary :
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/06/28 1.0.0 sheng.zheng
*
*/
@Service
public class ChangeNotifyServiceImpl implements ChangeNotifyService {
// ID
private Map<Integer,Integer> changeNotifyMap = new HashMap<Integer,Integer>();
/**
*
* @methodName : getChangeNotifyInfo
* @description : ID
* @param userId : ID
* @return : 0 , bitmap 。 :
* bit0: : , ;
* bit1: : , ;
* bit2: : , ;
* bit3: : , ;
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/06/28 1.0.0 sheng.zheng
*
*/
@Override
public Integer getChangeNotifyInfo(Integer userId) {
Integer changeNotifyInfo = 0;
//
if (changeNotifyMap.containsKey(userId)) {
changeNotifyInfo = changeNotifyMap.get(userId);
// ,
synchronized(changeNotifyMap) {
changeNotifyMap.remove(userId);
}
}
return changeNotifyInfo;
}
/**
*
* @methodName : setChangeNotifyInfo
* @description : ,
* @param userId : ID
* @param changeNotifyInfo :
* bit0: : , ;
* bit1: : , ;
* bit2: : , ;
* bit3: : , ;
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/06/28 1.0.0 sheng.zheng
*
*/
@Override
public void setChangeNotifyInfo(Integer userId,Integer changeNotifyInfo) {
//
if (changeNotifyMap.containsKey(userId)) {
// ,
//
Integer oldChangeNotifyInfo = changeNotifyMap.get(userId);
// 。bitmap ,
Integer newChangeNotifyInfo = oldChangeNotifyInfo | changeNotifyInfo;
// ,
synchronized(changeNotifyMap) {
changeNotifyMap.put(userId,newChangeNotifyInfo);
}
}else {
// ,
changeNotifyMap.put(userId,changeNotifyInfo);
}
}
}
*8195:여기 서 알림 유형 을 변경 하고 사용 하 는 demo 프로젝트 와 관련 되 며 현재 4 가지 변경 알림 유형 을 정의 합 니 다.실제로 권한 관련 변경 외 에 도 세 션 캐 시 필드 와 관련 된 변경 사항 이 있 으 므 로 알림 이 필요 합 니 다.그렇지 않 으 면 사용 자 는 오래된 데 이 터 를 사용 하고 있 습 니 다.3.2 알림 유형 변경 대상 을 전체 설정 서비스 대상 에 포함 시 켜 관리
전체 설정 서비스 클래스 GlobalConfigService 는 전체 설정 서비스 대상 을 관리 하고 서비스 인터페이스 류 코드 는 다음 과 같 습 니 다.
package com.abc.questInvest.service;
/**
* @className : GlobalConfigService
* @description :
* @summary :
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/06/02 1.0.0 sheng.zheng
*
*/
public interface GlobalConfigService {
/**
*
* @methodName : loadData
* @description :
* @return : true, false
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/06/02 1.0.0 sheng.zheng
*
*/
public boolean loadData();
// TableCodeConfigService
public TableCodeConfigService getTableCodeConfigService();
// SysParameterService
public SysParameterService getSysParameterService();
// FunctionTreeService
public FunctionTreeService getFunctionTreeService();
// RoleFuncRightsService
public RoleFuncRightsService getRoleFuncRightsService();
// ChangeNotifyService
public ChangeNotifyService getChangeNotifyService();
}
서비스 실현 류 GlobalConfigServiceImpl,코드 는 다음 과 같 습 니 다.
package com.abc.questInvest.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.abc.questInvest.service.ChangeNotifyService;
import com.abc.questInvest.service.FunctionTreeService;
import com.abc.questInvest.service.GlobalConfigService;
import com.abc.questInvest.service.RoleFuncRightsService;
import com.abc.questInvest.service.SysParameterService;
import com.abc.questInvest.service.TableCodeConfigService;
/**
* @className : GlobalConfigServiceImpl
* @description : GlobalConfigService
* @summary :
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/06/02 1.0.0 sheng.zheng
*
*/
@Service
public class GlobalConfigServiceImpl implements GlobalConfigService{
//ID
@Autowired
private TableCodeConfigService tableCodeConfigService;
//
@Autowired
private SysParameterService sysParameterService;
//
@Autowired
private FunctionTreeService functionTreeService;
//
@Autowired
private RoleFuncRightsService roleFuncRightsService;
//
@Autowired
private ChangeNotifyService changeNotifyService;
/**
*
* @methodName : loadData
* @description :
* @return : true, false
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/06/02 1.0.0 sheng.zheng
*
*/
@Override
public boolean loadData() {
boolean bRet = false;
// table_code_config
bRet = tableCodeConfigService.loadData();
if (!bRet) {
return bRet;
}
// sys_parameters
bRet = sysParameterService.loadData();
if (!bRet) {
return bRet;
}
//changeNotifyService ,
// , , , Session
// function_tree
bRet = functionTreeService.loadData();
if (!bRet) {
return bRet;
}
// role_func_rights
//
roleFuncRightsService.setFunctionTree(functionTreeService.getFunctionTree());
//
bRet = roleFuncRightsService.loadData();
if (!bRet) {
return bRet;
}
return bRet;
}
// TableCodeConfigService
@Override
public TableCodeConfigService getTableCodeConfigService() {
return tableCodeConfigService;
}
// SysParameterService
@Override
public SysParameterService getSysParameterService() {
return sysParameterService;
}
// FunctionTreeService
@Override
public FunctionTreeService getFunctionTreeService() {
return functionTreeService;
}
// RoleFuncRightsService
@Override
public RoleFuncRightsService getRoleFuncRightsService() {
return roleFuncRightsService;
}
// ChangeNotifyService
@Override
public ChangeNotifyService getChangeNotifyService() {
return changeNotifyService;
}
}
GlobalConfigServiceImpl 류 는 많은 설정 서비스 류 를 관 리 했 는데 여 기 는 주로 Change Notify Service 류 대상 에 주목 합 니 다.3.3,ServletContext 를 사용 하여 전역 설정 서비스 클래스 대상 관리
전체 설정 서비스 류 는 응용 이 시 작 될 때 Spring 용기 에 불 러 옵 니 다.이렇게 하면 공 유 를 실현 하고 데이터 베이스 에 대한 접근 압력 을 줄 일 수 있 습 니 다.
응용 프로그램 Listener 류 를 실현 합 니 다.코드 는 다음 과 같 습 니 다.
package com.abc.questInvest;
import javax.servlet.ServletContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
import com.abc.questInvest.service.GlobalConfigService;
/**
* @className : ApplicationStartup
* @description :
*
*/
@Component
public class ApplicationStartup implements ApplicationListener<ContextRefreshedEvent>{
// ,
private GlobalConfigService globalConfigService = null;
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
try {
if(contextRefreshedEvent.getApplicationContext().getParent() == null){
//root application context parent.
System.out.println("======== ==================");
// ApplicationContext WebApplicationContext
WebApplicationContext webApplicationContext =
(WebApplicationContext)contextRefreshedEvent.getApplicationContext();
// webApplicationContext servletContext
ServletContext servletContext = webApplicationContext.getServletContext();
//
globalConfigService = (GlobalConfigService)webApplicationContext.getBean(GlobalConfigService.class);
//
boolean bRet = globalConfigService.loadData();
if (false == bRet) {
System.out.println(" ");
return;
}
//======================================================================
// servletContext
servletContext.setAttribute("GLOBAL_CONFIG_SERVICE", globalConfigService);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
시동 클래스 에 이 응용 탐지 기 ApplicationStartup 을 추가 합 니 다.
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(QuestInvestApplication.class);
springApplication.addListeners(new ApplicationStartup());
springApplication.run(args);
}
현재 GlobalConfigService 형식의 전역 변수 globalConfigService 가 있 습 니 다.3.4 변경 통지 발송
여기 서 두 가지 예 를 들 어 변경 통 지 를 보 낸 예 를 설명 한다.이 두 가지 예 는 모두 사용자 관리 모듈,UserManServiceImpl 류 에 있다.
1)관리자 가 사용자 정 보 를 수정 하면 권한 관련 항목 에 변동 이 생 길 수 있 습 니 다.2)사용 자 를 사용 하지 않 고 변경 통 지 를 보 냈 습 니 다.
『8195』알림 을 보 내 는 관련 코드 는 다음 과 같 습 니 다.
/**
*
* @methodName : editUser
* @description :
* @param userInfo :
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/06/08 1.0.0 sheng.zheng
* 2021/06/28 1.0.1 sheng.zheng
*
*/
@Override
public void editUser(HttpServletRequest request,UserInfo userInfo) {
//
checkValidForParams("editUser",userInfo);
//
String operatorName = (String) request.getSession().getAttribute("username");
userInfo.setOperatorName(operatorName);
//
userInfo.setLoginName(null);
userInfo.setSalt(null);
userInfo.setPasswd(null);
//
Integer userId = userInfo.getUserId();
UserInfo oldUserInfo = userManDao.selectUserByKey(userId);
//
try {
userManDao.updateSelective(userInfo);
}catch(Exception e) {
e.printStackTrace();
log.error(e.getMessage());
throw new BaseException(ExceptionCodes.USERS_EDIT_USER_FAILED);
}
//
Integer changeFlag = 0;
if (userInfo.getRoles() != null) {
if(oldUserInfo.getRoles() != userInfo.getRoles()) {
// ,bit0
changeFlag |= 0x01;
}
}
if (userInfo.getDeptId() != null) {
if (oldUserInfo.getDeptId() != userInfo.getDeptId()) {
// ID ,bit3
changeFlag |= 0x08;
}
}
if (changeFlag > 0) {
//
//
ServletContext servletContext = request.getServletContext();
GlobalConfigService globalConfigService = (GlobalConfigService)servletContext.getAttribute("GLOBAL_CONFIG_SERVICE");
globalConfigService.getChangeNotifyService().setChangeNotifyInfo(userId, changeFlag);
}
}
/**
*
* @methodName : disableUser
* @description :
* @param params : map , :
* {
* "userId" : 1
* }
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/06/08 1.0.0 sheng.zheng
* 2021/06/28 1.0.1 sheng.zheng
*
*/
@Override
public void disableUser(HttpServletRequest request,Map<String,Object> params) {
//
checkValidForParams("disableUser",params);
UserInfo userInfo = new UserInfo();
//
String operatorName = (String) request.getSession().getAttribute("username");
// userInfo
Integer userId = (Integer)params.get("userId");
userInfo.setUserId(userId);
userInfo.setOperatorName(operatorName);
//
userInfo.setDeleteFlag((byte)1);
//
try {
userManDao.updateEnable(userInfo);
}catch(Exception e) {
e.printStackTrace();
log.error(e.getMessage());
throw new BaseException(ExceptionCodes.USERS_EDIT_USER_FAILED);
}
// ,
//
ServletContext servletContext = request.getServletContext();
GlobalConfigService globalConfigService = (GlobalConfigService)servletContext.getAttribute("GLOBAL_CONFIG_SERVICE");
// :bit2
globalConfigService.getChangeNotifyService().setChangeNotifyInfo(userId, 0x04);
}
본 demo 프로젝트 의 캐릭터 가 상대 적 으로 적 고 사용자 캐릭터 관계 표를 사용 하지 않 고 bitmap 인 코딩 을 사 용 했 습 니 다.캐릭터 ID 의 수 치 는 2^n 이 고 사용자 캐릭터 조합 roles 필드 는 Integer 값 입 니 다.예 를 들 어 roles=7 은 캐릭터 ID 조합=[1,2,4]을 나타 낸다.또한 캐릭터 의 기능 권한 집합 을 수정 하면 영향 을 받 은 사용자 ID 목록 을 조회 하고 순서대로 알림 을 보 내 유사 하 게 처리 할 수 있 습 니 다.
3.5.응답 메시지 수정
Response 응답 메시지 체 는 BaseResponse 이 고 코드 는 다음 과 같 습 니 다.
package com.abc.questInvest.vo.common;
import lombok.Data;
/**
* @className : BaseResponse
* @description :
* @summary :
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/05/31 1.0.0 sheng.zheng
* 2021/06/28 1.0.1 sheng.zheng
*
*/
@Data
public class BaseResponse<T> {
//
private int code;
//
private String message;
//
private T data;
//
private Page page;
//
private Additional additional;
}
BaseResponse 류 는 additional 형식의 additional 속성 필드 를 추가 하여 추가 정 보 를 출력 합 니 다.Additional 류 의 정 의 는 다음 과 같다.
package com.abc.questInvest.vo.common;
import lombok.Data;
/**
* @className : Additional
* @description :
* @summary :
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/06/28 1.0.0 sheng.zheng
*
*/
@Data
public class Additional {
// ,
private int notifycode;
//
private String notification;
// token
private String token;
//
private String rights;
}
*8195°추가 정보 류 Additional 에서 각 속성 필드 에 대한 설명:
//
USER_RIGHTS_CHANGED(51, "message.USER_RIGHTS_CHANGED", " "),
; //end enum
ExceptionCodes(int code, String messageId, String message) {
this.code = code;
this.messageId = messageId;
this.message = message;
}
『8195』AuthorizationAspect 는 감 권 인증 의 절단면 류 이 고 코드 는 다음 과 같다.
package com.abc.questInvest.aop;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.abc.questInvest.common.constants.Constants;
import com.abc.questInvest.common.utils.Utility;
import com.abc.questInvest.dao.UserManDao;
import com.abc.questInvest.entity.FunctionInfo;
import com.abc.questInvest.entity.UserInfo;
import com.abc.questInvest.exception.BaseException;
import com.abc.questInvest.exception.ExceptionCodes;
import com.abc.questInvest.service.GlobalConfigService;
import com.abc.questInvest.service.LoginService;
import com.abc.questInvest.vo.TreeNode;
import com.abc.questInvest.vo.common.Additional;
import com.abc.questInvest.vo.common.BaseResponse;
/**
* @className : AuthorizationAspect
* @description :
* @summary : AOP, token
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/06/06 1.0.0 sheng.zheng
* 2021/06/28 1.0.1 sheng.zheng , afterReturning
*
*/
@Aspect
@Component
@Order(2)
public class AuthorizationAspect {
@Autowired
private UserManDao userManDao;
//
@Pointcut("execution(public * com.abc.questInvest.controller..*.*(..))" +
"&& !execution(public * com.abc.questInvest.controller.LoginController.*(..))" +
"&& !execution(public * com.abc.questInvest.controller.QuestInvestController.*(..))")
public void verify(){}
@Before("verify()")
public void doVerify(){
ServletRequestAttributes attributes=(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request=attributes.getRequest();
// ================================================================================
// token
// header token
String token = request.getHeader("Authorization");
if (null == token || token.equals("")){
//return;
throw new BaseException(ExceptionCodes.TOKEN_IS_NULL);
}
// session token
String sessionToken = (String)request.getSession().getAttribute("token");
// session ,
if (null == sessionToken || sessionToken.equals("")) {
throw new BaseException(ExceptionCodes.TOKEN_WRONG);
}
// token
if(!token.equals(sessionToken)) {
// token session token
throw new BaseException(ExceptionCodes.TOKEN_WRONG);
}
long expireTime = (long)request.getSession().getAttribute("expireTime");
//
long time = System.currentTimeMillis();
if (time > expireTime) {
// token
throw new BaseException(ExceptionCodes.TOKEN_EXPIRED);
}else {
//token ,
long newExpiredTime = time + Constants.TOKEN_EXPIRE_TIME * 1000;
request.getSession().setAttribute("expireTime", newExpiredTime);
}
// ============================================================================
//
// ID
Integer userId = (Integer)request.getSession().getAttribute("userId");
//
ServletContext servletContext = request.getServletContext();
GlobalConfigService globalConfigService = (GlobalConfigService)servletContext.getAttribute("GLOBAL_CONFIG_SERVICE");
//=================== ==============================================
//
Integer changeNotifyInfo = globalConfigService.getChangeNotifyService().getChangeNotifyInfo(userId);
//
boolean rightsChangedFlag = false;
if (changeNotifyInfo > 0) {
//
if ((changeNotifyInfo & 0x09) > 0) {
//bit0: ,
//bit3: ,
//mask 0b1001 = 0x09
// , ; 。
UserInfo userInfo = userManDao.selectUserByKey(userId);
// Session
request.getSession().setAttribute("roles", userInfo.getRoles());
request.getSession().setAttribute("deptId", userInfo.getDeptId());
if ((changeNotifyInfo & 0x01) > 0) {
//
rightsChangedFlag = true;
}
}else if((changeNotifyInfo & 0x02) > 0) {
//bit1: ,
//
rightsChangedFlag = true;
}else if((changeNotifyInfo & 0x04) > 0) {
//bit2: ,
// token,
request.getSession().setAttribute("token", "");
// , :Forbidden
throw new BaseException(ExceptionCodes.ACCESS_FORBIDDEN);
}
if (rightsChangedFlag == true) {
// Session, afterReturning
request.getSession().setAttribute("rightsChanged", 1);
}
}
//=================== ==============================================
// session
Integer roles = (Integer)request.getSession().getAttribute("roles");
// url
String servletPath = request.getServletPath();
// url
Integer rights = globalConfigService.getRoleFuncRightsService().getRoleUrlRights(Utility.parseRoles(roles), servletPath);
if (rights == 0) {
// , , :Forbidden
throw new BaseException(ExceptionCodes.ACCESS_FORBIDDEN);
}
}
@AfterReturning(value="verify()" ,returning="result")
public void afterReturning(BaseResponse result) {
// BaseResponse ,
// Session
ServletRequestAttributes sra = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = sra.getRequest();
Integer rightsChanged = (Integer)request.getSession().getAttribute("rightsChanged");
if (rightsChanged != null && rightsChanged == 1) {
// ,
//
Additional additional = new Additional();
additional.setNotifycode(ExceptionCodes.USER_RIGHTS_CHANGED.getCode());
additional.setNotification(ExceptionCodes.USER_RIGHTS_CHANGED.getMessage());
// token
String loginName = (String)request.getSession().getAttribute("username");
String token = LoginService.generateToken(loginName);
additional.setToken(token);
// token, url token
request.getSession().setAttribute("token", token);
//
Integer roles = (Integer)request.getSession().getAttribute("roles");
ServletContext servletContext = request.getServletContext();
GlobalConfigService globalConfigService = (GlobalConfigService)servletContext.getAttribute("GLOBAL_CONFIG_SERVICE");
//
List<Integer> roleList = Utility.parseRoles(roles);
TreeNode<FunctionInfo> rolesFunctionTree =
globalConfigService.getRoleFuncRightsService().
getRoleRights(roleList);
additional.setRights(rolesFunctionTree.toString());
// response
result.setAdditional(additional);
// Session rightsChanged
request.getSession().removeAttribute("rightsChanged");
}
}
}
AuthorizationAspect 류 는 절 점 verify()를 정 의 했 고@Before 강 화 는 감 권 검증 에 사용 되 며 변경 알림 정보 에 대한 처 리 를 추 가 했 습 니 다.또한 Session 을 이용 하여 rights Changed 속성 필드 로 전단 에 알려 야 할 로 고 를 기록 하고@AfterReturning 후 강화 에서 이 속성 필드 의 값 에 따라 한 단계 처리 합 니 다.@Before 강 화 된 doVerify 방법 에서 캐릭터 조합 이 바 뀌 었 지만 이 url 에 접근 할 수 있 는 권한 이 있 을 경우 후속 처 리 를 계속 합 니 다.이렇게 하면 업 무 를 중단 하지 않 습 니 다.이 url 에 접근 할 수 있 는 권한 이 없 으 면 접근 제한 이상 정 보 를 되 돌려 주 고 접근 제한 페이지(403 Forbidden 페이지 와 유사)를 전단 에 표시 합 니 다.
는 백업 증강@AfterReturning 에서 반환 값 형식 을 제한 합 니 다.이 요청 에 응 하 는 유형 이 BaseResponse 형식 이 라면 reponse 메시지 체 를 수정 하고 알림 정 보 를 추가 합 니 다.그렇지 않 으 면 처리 하지 않 고 다음 url 요청 을 기다 릴 것 입 니 다.형식 이 BaseResponse 형식 일 때 까지 기다 릴 것 입 니 다.사용자 정의 response 의 header 방식 을 사용 할 수도 있 습 니 다.기다 릴 필요 가 없습니다.
generateToken 방법 은 LoginService 류 의 정적 방법 으로 사용자 token 을 생 성 하 는 데 사 용 됩 니 다.
유 틸 리 티 의 parseRoles 방법 은 bitmap 인 코딩 의 roles 를 캐릭터 ID 의 목록 으로 해석 하 는 것 입 니 다.코드 는 다음 과 같 습 니 다.
//========================= ======================================
/**
*
* @methodName : parseRoles
* @description :
* @param roles :
* @return : ID
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/06/24 1.0.0 sheng.zheng
*
*/
public static List<Integer> parseRoles(int roles){
List<Integer> roleList = new ArrayList<Integer>();
int newRoles = roles;
int bit0 = 0;
int roleId = 0;
for (int i = 0; i < 32; i++) {
// 0,
if (newRoles == 0) {
break;
}
//
bit0 = newRoles & 0x01;
if (bit0 == 1) {
// 1, i
roleId = 1 << i;
roleList.add(roleId);
}
//
newRoles = newRoles >> 1;
}
return roleList;
}
getRoleRights 방법 은 캐릭터 기능 권한 서비스 류 RoleFuncRightsService 의 방법 으로 List 유형의 캐릭터 ID 목록 에 따라 기능 권한 트 리 를 빠르게 가 져 오 는 기능 을 제공 합 니 다.기능 권한 트 리 TreeNode 유형 에 대해 서 는 다음 을 참조 하 시기 바 랍 니 다《자바 유 니 버 설 트 리 구조 데이터 관리》
Spring Boot 의 동적 권한 변경 실현 에 관 한 전체 방안 에 관 한 글 은 여기까지 입 니 다.더 많은 Spring Boot 동적 권한 내용 은 이전 글 을 검색 하거나 아래 글 을 계속 찾 아 보 세 요.앞으로 도 많은 응원 부 탁 드 리 겠 습 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
[MeU] Hashtag 기능 개발➡️ 기존 Tag 테이블에 존재하지 않는 해시태그라면 Tag , tagPostMapping 테이블에 모두 추가 ➡️ 기존에 존재하는 해시태그라면, tagPostMapping 테이블에만 추가 이후에 개발할 태그 기반 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.