if different businesses have been designed to be controlled by request parameters, it is recommended to use the custom permission control of shiro to parse the corresponding business code and carry out permission control. This method is more flexible, not only can write dead permission rules, but also can cooperate with the database to make dynamic rule control.
all requests are intercepted, and the corresponding shiro configuration: / * * = perms;
inherits the org.apache.shiro.authz.Permission, rewrite implies method for permission verification.
Custom filter, override
isAccessAllowed
Custom realm, rewriting
doGetAuthorizationInfo
< H2 > I need to authorize according to the link parameters, and this is how I do it. < / H2 >
public class CustomRealm extends AuthorizingRealm
here is the authorization code
/**
*
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
logger.info("------------doGetAuthorizationInfo");
User user = (User) principalCollection.getPrimaryPrincipal();
List<String> userRoles = new ArrayList<String>();
Set<String> categoryIds = new HashSet<>();
QueryWrapper queryUserWrapper = new QueryWrapper();
queryUserWrapper.eq("uuid",user.getUuid());
user = userService.getOne(queryUserWrapper);
if(null != user){
Ugroup ugroup = ugroupService.getById(user.getGroupId());
userRoles.add(ugroup.getName());
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("idx_group_id",ugroup.getId());
List<GroupCategory> groupCategories = groupCategoryService.list(queryWrapper);
if (groupCategories.size() > 0){
for (GroupCategory groupCategory : groupCategories){
categoryIds.add(groupCategory.getCategoryId().toString());
}
}
}else{
throw new AuthorizationException();
}
//
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.addRoles(userRoles);
authorizationInfo.addStringPermissions(categoryIds);
return authorizationInfo;
}
< H2 > overr
ide isAccessAllowed in filter < / H2 >
public class JWTFilter extends AuthorizationFilter {
...
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
logger.info("-----isAccessAllowed----");
if (isLoginAttempt(request, response)) {
try {
executeLogin(request, response);
} catch (Exception e) {
response401(response);
}
}
String id = request.getParameter("id");
Subject subject = getSubject(request,response);
boolean flag = subject.isPermitted(id);
return flag;
}
...
}
< H2 > requirements: authorize access to different types of articles for users belonging to different user groups < / H2 >
< H2 > implementation
idea: < / H2 >
the user information is obtained according to token in doGetAuthorizationInfo, the article types that can be accessed from the database are jointly queried, id, is added to the user rights, the parameters in the user access link are obtained in isAccessAllowed, and
is called.
subject.isPermitted(id);
determine whether you have this permission or not.
< H2 > Note: the subject.login (token); method must be called before subject.isPermitted (id) is called, otherwise authorization will not be carried out during isPermitted < / H2 >
< H2 > paste all the codes below < / H2 >
< H2 > CustomRealm.java < / H2 >
package com.zyc.shiro;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zyc.constant.CommonConstant;
import com.zyc.dao.GroupCategoryMapper;
import com.zyc.dao.UgroupMapper;
import com.zyc.entity.GroupCategory;
import com.zyc.entity.Ugroup;
import com.zyc.entity.User;
import com.zyc.redis.JwtRedisDAO;
import com.zyc.service.GroupCategoryService;
import com.zyc.service.UgroupService;
import com.zyc.service.UserService;
import com.zyc.util.JWTUtils;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationException;
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;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.*;
/**
*
*/
public class CustomRealm extends AuthorizingRealm {
static Logger logger = LoggerFactory.getLogger(CustomRealm.class);
@Autowired
private UgroupService ugroupService;
@Autowired
private GroupCategoryService groupCategoryService;
@Autowired
private UserService userService;
@Autowired
private JwtRedisDAO jwtRedisDAO;
/**
* Shiro
*/
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof JWTToken;
}
/**
*
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
logger.info("------------doGetAuthorizationInfo");
User user = (User) principalCollection.getPrimaryPrincipal();
List<String> userRoles = new ArrayList<String>();
Set<String> categoryIds = new HashSet<>();
QueryWrapper queryUserWrapper = new QueryWrapper();
queryUserWrapper.eq("uuid",user.getUuid());
user = userService.getOne(queryUserWrapper);
if(null != user){
Ugroup ugroup = ugroupService.getById(user.getGroupId());
userRoles.add(ugroup.getName());
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("idx_group_id",ugroup.getId());
List<GroupCategory> groupCategories = groupCategoryService.list(queryWrapper);
if (groupCategories.size() > 0){
for (GroupCategory groupCategory : groupCategories){
categoryIds.add(groupCategory.getCategoryId().toString());
}
}
}else{
throw new AuthorizationException();
}
//
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.addRoles(userRoles);
authorizationInfo.addStringPermissions(categoryIds);
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
logger.info("CustomRealm------------------doGetAuthenticationInfo");
Map claims = JWTUtils.getClaims(CommonConstant.JWT_SECRET, (String) authenticationToken.getPrincipal());
if (claims == null) {
//
throw new UnknownAccountException();
}
String uuid = (String) claims.get("uuid");
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("uuid",uuid);
User user = userService.getOne(queryWrapper);
//logger.info(user.toString());
if(null == user){
throw new UnknownAccountException();
}
String token = jwtRedisDAO.get(CommonConstant.ADMIN_JWT_PREFIX + uuid);
//logger.info("token {}", authenticationToken.getPrincipal());
if (token == null || !token.equals(authenticationToken.getPrincipal())) {
throw new AuthorizationException();
}
//AuthenticatingRealmCredentialsMatcher
return new SimpleAuthenticationInfo(
//
user,
authenticationToken.getPrincipal(),
//realm name
getName()
);
}
}
< H2 > JWTFilter.java < / H2 >
package com.zyc.shiro;
import com.alibaba.fastjson.JSON;
import com.zyc.exception.enums.ErrorEnums;
import com.zyc.vo.RestResult;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class JWTFilter extends AuthorizationFilter {
private static Logger logger = LoggerFactory.getLogger(JWTFilter.class);
/**
*
* headerAuthorization
*/
//@Override
protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
logger.info("-----isLoginAttempt----");
HttpServletRequest req = (HttpServletRequest) request;
String authorization = req.getHeader("Authorization");
return authorization != null;
}
/**
*
*/
//@Override
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
logger.info("-----executeLogin----");
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String authorization = httpServletRequest.getHeader("Authorization");
JWTToken token = new JWTToken(authorization);
// realm
getSubject(request, response).login(token);
// true
return true;
}
/**
*
*
* true
* GET /article
*
* false
* trueController subject.isAuthenticated()
* @RequiresAuthentication
* GET,POST()
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
logger.info("-----isAccessAllowed----");
if (isLoginAttempt(request, response)) {
try {
executeLogin(request, response);
} catch (Exception e) {
response401(response);
}
}
String id = request.getParameter("id");
Subject subject = getSubject(request,response);
boolean flag = subject.isPermitted(id);
return flag;
}
/**
*
*/
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
logger.info("-----preHandle----");
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
httpServletResponse.setHeader("Access-Control-Allow-Methods", httpServletRequest.getMethod());
httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
// optionoption
if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
httpServletResponse.setStatus(HttpStatus.OK.value());
return true;
}
return super.preHandle(request, response);
}
/**
* onAccessDenied:; true ; false
* @param servletRequest
* @param servletResponse
* @return
* @throws Exception
*/
@Override
protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) {
logger.info(" isAccessAllowed false method onAccessDenied ");
try {
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
RestResult result = new RestResult();
result.setCode(ErrorEnums.PERMISSION_DENIED.getCode());
result.setMsg(ErrorEnums.PERMISSION_DENIED.getMsg());
httpServletResponse.setContentType("application/json;charset=UTF-8");
PrintWriter out = httpServletResponse.getWriter();
out.print(JSON.toJSONString(result));
out.flush();
out.close();
} catch (IOException e) {
logger.error(e.getMessage());
}
// false
return false;
}
/**
* code401
*/
private void response401(ServletResponse resp) {
logger.info("-----response401----");
try {
HttpServletResponse httpServletResponse = (HttpServletResponse) resp;
RestResult result = new RestResult();
result.setCode(ErrorEnums.TOKEN_MISS.getCode());
result.setMsg(ErrorEnums.TOKEN_MISS.getMsg());
httpServletResponse.setContentType("application/json;charset=UTF-8");
PrintWriter out = httpServletResponse.getWriter();
out.print(JSON.toJSONString(result));
out.flush();
out.close();
} catch (IOException e) {
logger.error(e.getMessage());
}
}
}
< H2 > JWTToken.java < / H2 >
package com.zyc.shiro;
import org.apache.shiro.authc.AuthenticationToken;
public class JWTToken implements AuthenticationToken {
private String token;
public JWTToken(String token) {
this.token = token;
}
@Override
public Object getPrincipal() {
return token;
}
@Override
public Object getCredentials() {
return getPrincipal();
}
}
< H2 > ShiroConfigurer.java < / H2 >
package com.zyc;
import com.zyc.shiro.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.ModularRealmAuthorizer;
import org.apache.shiro.authz.permission.PermissionResolver;
import org.apache.shiro.authz.permission.RolePermissionResolver;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import java.util.*;
@Configuration
public class ShiroConfigurer {
private static final Logger logger = LoggerFactory.getLogger(ShiroConfigurer.class);
/**
* ShiroWebFactory :shiroFilter<br />
*
* @param securityManager
* @return
*/
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
logger.info("ShiroWeb-->shiroFilter {}", ShiroFilterFactoryBean.class);
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// Shiro,
shiroFilterFactoryBean.setSecurityManager(securityManager);
// (URL),,Web"/login.jsp"
// shiroFilterFactoryBean.setLoginUrl("/login")
// ,
// shiroFilterFactoryBean.setSuccessUrl("/index")
// ,
// shiroFilterFactoryBean.setUnauthorizedUrl("/pages/403")
/* shiro,FormAuthenticationFilterFormAuthenticationFilter
**
*/
/*shiro Map
* Mapkey(xmlvalue)'/'HttpServletRequest.getContextPath()
* anon:,,.do.jsp*,login.jsp?main
* authc:,Shiroorg.apache.shiro.web.filter.authc.FormAuthenticationFilter
*/
// jwt
Map filterMap = new HashMap();
filterMap.put("jwt", new JWTFilter());
shiroFilterFactoryBean.setFilters(filterMap);
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
// ,Shiro
// <!-- /** -->:
// <!-- authc:url; anon:url-->
// filterChainDefinitionMap.put("/webui/**", "anon")
// filterChainDefinitionMap.put("/webjars/**", "anon")
//filterChainDefinitionMap.put("/sys/login", "anon");
//filterChainDefinitionMap.put("/sys/logout", "anon");
//filterChainDefinitionMap.put("/token/callback", "anon");
//filterChainDefinitionMap.put("/dist", "anon");
//filterChainDefinitionMap.put("/download/excel", "anon");
//api
filterChainDefinitionMap.put("/user/login", "anon");
filterChainDefinitionMap.put("/**", "authc");
// JWT Filter
filterChainDefinitionMap.put("/**", "jwt");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public JWTFilter jwtFilter() {
return new JWTFilter();
}
/**
* Shiro Realm AuthorizingRealmRealm,Shiro
*
* @param
* @return managerRealm
*/
@Bean
public CustomRealm userRealm() {
CustomRealm userRealm = new CustomRealm();
// realm,credentialsMatcher
// userRealm.setCredentialsMatcher(hashedCredentialsMatcher())
userRealm.setCachingEnabled(false);
//
return userRealm;
}
/**
* bean
*
* @return
* @Bean(name = "securityManager")
*/
@Bean
public SecurityManager securityManager() {
logger.info("ShiroWeb-->securityManager {}", ShiroFilterFactoryBean.class);
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm());
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
// session
DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
securityManager.setSubjectDAO(subjectDAO);
return securityManager;
}
/**
*
* ShiroSimpleAuthenticationInfo
* doGetAuthenticationInfo;
*
*
*
* @return
*/
@Bean(name = "credentialsMatcher")
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("SHA-512");
// md5(md5(""))
hashedCredentialsMatcher.setHashIterations(2);
//storedCredentialsHexEncodedtrueHex;falseBase64
hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
return hashedCredentialsMatcher;
}
/**
* Shiro
*
* @return
*/
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
* Shiro(@RequiresRoles,@RequiresPermissions),SpringAOPShiro,
* bean(DefaultAdvisorAutoProxyCreator()AuthorizationAttributeSourceAdvisor)
*
* @return
*/
@Bean
@DependsOn({"lifecycleBeanPostProcessor"})
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
advisorAutoProxyCreator.setUsePrefix(true);
return advisorAutoProxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor;
}
}
< H2 > pom.xml < / H2 >
<!--aop-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--jwt-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
<!-- Shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>