Recently the company's services have such a demand: there are two sets of back-office services in the background when requested, it will start with permissions gateway layer interception. According to the menu owned by the currently logged in user, role, and url address request to intercept can request to another service address. Gateway layer used shiro rights management, has a good package roles, permissions and account number. But it has been thought to understand the issue of interception of uri. Shiro then see the source code from our existing login looks. Finally managed to find a solution
shiro at login time, login method is the use of the Subject.
Subject currentLoginUser = SecurityUtils.getSubject();
//A:是否已经登录
if(currentLoginUser.isAuthenticated()) {
Boolean isAjax = (Boolean) request.getAttribute("X_IS_AJAX");
if( isAjax ) {
return AjaxResponse.success( null );
}else {
response.sendRedirect(homepageUrl);
return null;
}
}
//B:查询用户信息
CarAdmUser user = carAdmUserExMapper.queryByAccount(username,null);
if(user==null){
return AjaxResponse.fail(RestErrorCode.USER_NOT_EXIST) ;
}
//C:密码不正确
String enc_pwd = PasswordUtil.md5(password, user.getAccount());
if(!enc_pwd.equalsIgnoreCase(user.getPassword())) {
AjaxResponse.fail return (RestErrorCode.USER_PASSWORD_WRONG);
}
// E: user state
IF (! user.getStatus () = null && user.getStatus () intValue () == 100.) {
return AjaxResponse.fail (RestErrorCode.USER_INVALID );
}
// F.: performing log
the try {
// Log Shiro
UsernamePasswordToken new new token = UsernamePasswordToken (username, password.toCharArray ()); currentLoginUser.login (token);
// record all user login session ID to support " system management "function in automatic session cleanup
String sessionId = (String) currentLoginUser.getSession () getId ();.
redisSessionDAO.saveSessionIdOfLoginUser (username, sessionId);
redisTemplate.delete (redis_login_key);
redisTemplate.delete (redis_getmsgcode_key);
}catch(AuthenticationException aex) {
return AjaxResponse.fail(RestErrorCode.USER_LOGIN_FAILED) ;
}
//返回登录成功
Boolean isAjax = (Boolean) request.getAttribute("X_IS_AJAX");
if( isAjax ) {
return AjaxResponse.success( null );
}else {
response.sendRedirect(homepageUrl);
return null;
}
currentLoginUser.login (token); shiro is rewritten inside AuthorizingRealm ()
package com.sq.transportmanage.gateway.service.shiro.realm; import com.sq.transportmanage.gateway.dao.entity.driverspark.CarAdmUser; import com.sq.transportmanage.gateway.dao.mapper.driverspark.ex.SaasPermissionExMapper; import com.sq.transportmanage.gateway.dao.mapper.driverspark.ex.SaasRoleExMapper; import com.sq.transportmanage.gateway.service.auth.MyDataSourceService; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; org.springframework.beans.factory.annotation.Autowired Import; org.springframework.stereotype.Component Import; Import java.util.HashSet; Import java.util.List; Import java.util.Set; / ** authentication and rights ** / / ** * This is the shiro SSOLogin user acquisition configuration attribute * / @Component public class UsernamePasswordRealm the extends AuthorizingRealm { Private static Logger Logger = Final LoggerFactory.getLogger (UsernamePasswordRealm.class); @Autowired Private myDataSourceService myDataSourceService; @Autowired Private SaasPermissionExMapper saasPermissionExMapper; @Autowired Private SaasRoleExMapper saasRoleExMapper; / ** weight write: obtaining user authentication information ** / @Override AuthenticationInfo doGetAuthenticationInfo protected (AuthenticationToken AuthenticationToken) throws of AuthenticationException { logger.info ( "[acquired user authentication information start] AuthenticationToken =" + AuthenticationToken); the try { UsernamePasswordToken token = (UsernamePasswordToken) AuthenticationToken; CarAdmUser admuser = myDataSourceService.queryByAccount (token. getUsername ()); SSOLoginUser loginUser = new new SSOLoginUser (); // user currently logged loginUser.setId (adMUser.getUserId ()); // user ID loginUser.setLoginName (adMUser.getAccount ()); // login loginUser .setMobile (adMUser.getPhone ()); // phone number loginUser.setType (null); // loginUser.setName (adMUser.getUserName ()); // real name loginUser.setEmail (adMUser.getEmail ()); // email address loginUser.setStatus (adMUser.getStatus ()); // state loginUser.setAccountType (adMUser.getAccountType ()); // own account type: [100 ordinary users], [900 administrator] loginUser.setLevel (adMUser.getLevel ()); loginUser.setUuid (adMUser.getUuid ()); List <String> menuUrlList = saasPermissionExMapper.queryPermissionCodesOfUser (adMUser.getUserId ()); loginUser. setMenuUrlList (menuUrlList); // ------------------------------------------- -------------------------------------------------- data permission ------------ the BEGIN logger.info ( "[user authentication information acquired] =" + loginUser); return new new SimpleAuthenticationInfo (loginUser, authenticationToken.getCredentials (), this.getName ( )); } the catch (exception E) { logger.error ( "user authentication information acquired abnormal", E); return null; } } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { SSOLoginUser loginUser = (SSOLoginUser) principalCollection.getPrimaryPrincipal(); String account = loginUser.getLoginName(); //登录名 List<String> perms_string = saasPermissionExMapper.queryPermissionCodesOfUser( loginUser.getId() ); List<String> roles_string = saasRoleExMapper.queryRoleCodesOfUser( loginUser.getId() ); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); Set<String> roles = new HashSet<String>( roles_string ); authorizationInfo.setRoles( roles ); logger.info ( "[obtaining user authorization information (role)]" + Account + "=" + Roles); Set<String> perms = new HashSet<String>( perms_string ); authorizationInfo.setStringPermissions(perms); logger.info ( "[obtaining user authorization information (permission)]" + Account + "=" + PERMS); return authorizationInfo ; } @Override public Object getAuthorizationCacheKey (PrincipalCollection Principals) { SSOLoginUser loginUser = (SSOLoginUser) principals.getPrimaryPrincipal (); String Account = loginUser.getLoginName (); // login return "-AuthInfo -" + Account; } @Override public clearCachedAuthorizationInfo void (PrincipalCollection Principals) { super.clearCachedAuthorizationInfo (Principals); } @Override public void clearCachedAuthenticationInfo(PrincipalCollection principals) { super.clearCachedAuthenticationInfo(principals); } @Override public void clearCache(PrincipalCollection principals) { super.clearCache(principals); } }
This can be through the login information into shiro inside, the following menu is specific permissions. Normally, use the comments shiro
@RequiresPermissions (value = { "value" })
can be used normally. @RequiresPermissions source which is used aop way, by determining whether the value of a set value which determines whether there is authority (Reference: https://blog.csdn.net/xiewenfeng520/article/details/89447749 )
. But our project is somewhat different, this is the gateway layer, the authority is doing to configure the gateway, and then determine whether to jump to the specified url. I have thought a good day how to intercept the url, because the parameters of my table relationships inside a url address will not pass. Then after reading the source code to achieve shiro,
I found myself thinking no problem, but the url will pass. So plan changed this:
1) write an interceptor to intercept url address
2) Once logged in, the menu will contain the user's permission to put shiro inside
3) interceptor inside judgment, if the administrator directly through, if not to see whether the user has the permission.
Specific implementation code:
. 1) Zuul blockers:
package com.sq.transportmanage.gateway.api.web.filter; import com.alibaba.fastjson.JSONObject; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.sq.transportmanage.gateway.api.common.AuthEnum; import com.sq.transportmanage.gateway.service.shiro.realm.SSOLoginUser; import com.sq.transportmanage.gateway.service.shiro.session.WebSessionUtil; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.util.List; /** * @program: sq-union-manage * @description: AccessFilter * @author: zjw * @create: 2020-02-23 18:57 **/ @Component @RequiresPermissions("/") public class AccessFilter extends ZuulFilter { private static Logger logger = LoggerFactory.getLogger(AccessFilter.class); @Override public String filterType() { return "pre"; } @Override public int filterOrder() { return 1; } @Override public boolean shouldFilter() { return true; } @Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); logger.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString())); SSOLoginUser loginUser = WebSessionUtil.getCurrentLoginUser(); logger.info(String.format("%s loginUser %s", loginUser.getLoginName(), loginUser.getName())); /**用户是否有权限**/ boolean bl = false; //如果是管理员 直接通过 if(AuthEnum.MANAGE.getAuthId().equals(loginUser.getAccountType())){ bl = true; }else { String uri = request.getRequestURI().toString(); List <String> menuUrl loginUser.getMenuUrlList = (); IF (menuUrl.contains (URI)) { bl = true; } } IF (BL) { ctx.addZuulRequestHeader ( "user_token", JSONObject.toJSONString (loginUser)); } the else { ctx.setSendZuulResponse (to false); // filtering the request, without routing it ctx.setResponseStatusCode (401); / / error code is returned ctx.setResponseBody ( "{\" code \ ": 0, \" result \ ": \" authentication failed authentication gateway 2 \! "}"); // returns the contents of the error ctx.set ( " isSuccess ", to false); } // increase the TODO permission determination herein can return CTX; } }
2) shiro storage rights:
package com.sq.transportmanage.gateway.service.shiro.realm; import com.sq.transportmanage.gateway.dao.entity.driverspark.CarAdmUser; import com.sq.transportmanage.gateway.dao.mapper.driverspark.ex.SaasPermissionExMapper; import com.sq.transportmanage.gateway.dao.mapper.driverspark.ex.SaasRoleExMapper; import com.sq.transportmanage.gateway.service.auth.MyDataSourceService; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; org.springframework.beans.factory.annotation.Autowired Import; Import org.springframework.stereotype.Component; Import java.util.HashSet; Import java.util.List; Import java.util.Set; / * * * authentication and rights * / / * * * this is obtained shiro SSOLogin user configuration attributes * / @Component public class UsernamePasswordRealm the extends AuthorizingRealm { Private static Final Logger Logger = LoggerFactory.getLogger (UsernamePasswordRealm. class ); @Autowired Private myDataSourceService myDataSourceService; @Autowired PrivateSaasPermissionExMapper SaasPermissionExMapper; @Autowired Private SaasRoleExMapper saasRoleExMapper; / * * rewritten: obtaining user authentication information * * / @Override protected AuthenticationInfo doGetAuthenticationInfo (AuthenticationToken AuthenticationToken) throws of AuthenticationException { logger.info ( " [acquired user authentication information start] = AuthenticationToken " + AuthenticationToken); the try { UsernamePasswordToken token = (UsernamePasswordToken) AuthenticationToken; CarAdmUser admuser = new new myDataSourceService.queryByAccount (token.getUsername ()); LoginUser SSOLoginUser =SSOLoginUser (); // currently logged on user loginUser.setId (adMUser.getUserId ()); // user ID loginUser.setLoginName (adMUser.getAccount ()); // login loginUser.setMobile (adMUser.getPhone ()) ; // phone number loginUser.setName (adMUser.getUserName ()); // real name loginUser.setEmail (adMUser.getEmail ()); // mail address loginUser.setType ( null ); // loginUser.setStatus (admuser. the getStatus ()); // state loginUser.setAccountType (adMUser.getAccountType ()); // own account type: [100 ordinary users], [900 Administrator] loginUser.setLevel (adMUser.getLevel ()); loginUser.setUuid (adMUser.getUuid ( )); List <String> menuUrlList = saasPermissionExMapper.queryPermissionCodesOfUser (adMUser.getUserId ()); loginUser.setMenuUrlList (menuUrlList); // --------------------- -------------------------------------------------- ---------------------------------- data permission BEGIN logger.info ( " [to obtain user authentication information] = " + loginUser); return new newSimpleAuthenticationInfo (loginUser, authenticationToken.getCredentials (), the this .getName ()); } the catch (Exception E) { logger.error ( " acquired user authentication information abnormal " , E); return null ; } } @Override protected AuthorizationInfo doGetAuthorizationInfo (principalCollection principalCollection) { SSOLoginUser loginUser = (SSOLoginUser) principalCollection.getPrimaryPrincipal (); String the Account = loginUser.getLoginName (); // login List<String> perms_string = saasPermissionExMapper.queryPermissionCodesOfUser( loginUser.getId() ); List<String> roles_string = saasRoleExMapper.queryRoleCodesOfUser( loginUser.getId() ); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); Set<String> roles = new HashSet<String>( roles_string ); authorizationInfo.setRoles( roles ); logger.info( "[获取用户授权信息(角色)] "+account+"="+roles); Set<String> perms = new HashSet<String>( perms_string ); authorizationInfo.setStringPermissions(perms); logger.info( "[获取用户授权信息(权限)] "+account+"="+perms); return authorizationInfo; } @Override public Object getAuthorizationCacheKey(PrincipalCollection principals) { SSOLoginUser loginUser = (SSOLoginUser) principals.getPrimaryPrincipal(); String account = loginUser.getLoginName(); //登录名 return "-AuthInfo-"+account; } @Override public void clearCachedAuthorizationInfo(PrincipalCollection principals) { super.clearCachedAuthorizationInfo(principals); } @Override public void clearCachedAuthenticationInfo(PrincipalCollection principals) { super.clearCachedAuthenticationInfo(principals); } @Override public void clearCache(PrincipalCollection principals) { super.clearCache(principals); } }
Probably idea is this. . .