依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
放行接口的配置类
import com.datacvgproject.gsrobot.modules.oauth.app.oauth2.AppOAuth2Filter;
import com.datacvgproject.gsrobot.modules.oauth.app.oauth2.AppOAuth2Realm;
import com.datacvgproject.gsrobot.modules.oauth.sys.oauth2.OAuth2Filter;
import com.datacvgproject.gsrobot.modules.oauth.sys.oauth2.OAuth2Realm;
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.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
import java.util.*;
@Configuration
public class SysShiroConfig {
@Bean("securityManager")
public SecurityManager securityManager(OAuth2Realm oAuth2Realm, AppOAuth2Realm appOAuth2Realm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setAuthenticator(authenticator());
List<Realm> realms = new ArrayList<>();
realms.add(oAuth2Realm);
realms.add(appOAuth2Realm);
securityManager.setRealms(realms);
return securityManager;
}
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
Map<String, Filter> filters = new HashMap<>();
filters.put("app", new AppOAuth2Filter());
shiroFilter.setFilters(filters);
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/webjars/**", "anon");
filterMap.put("/druid/**", "anon");
filterMap.put("/sys/login", "anon");
filterMap.put("/swagger/**", "anon");
filterMap.put("/v2/api-docs", "anon");
filterMap.put("/swagger-ui.html", "anon");
filterMap.put("/swagger-resources/**", "anon");
filterMap.put("/captcha.jpg", "anon");
filterMap.put("/aaa.txt", "anon");
filterMap.put("/**/**/**/*.png", "anon");
filterMap.put("/sys/**", "oauth2");
filterMap.put("/console/**", "oauth2");
filterMap.put("/app/login", "anon");
filterMap.put("/app/loginWithPhoneNumber", "anon");
filterMap.put("/decode/wxapp/phone", "anon");
filterMap.put("/app/loginWithWatchCode", "anon");
filterMap.put("/websocket/**", "anon");
filterMap.put("/app/**", "app");
filterMap.put("/applets/**", "app");
shiroFilter.setFilterChainDefinitionMap(filterMap);
return shiroFilter;
}
@Bean("lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
@Bean
public CustomModularRealmAuthenticator authenticator(){
CustomModularRealmAuthenticator authenticator = new CustomModularRealmAuthenticator();
return authenticator;
}
}
过滤器,放行政策-请求头是否含有token
import com.datacvgproject.gsrobot.common.constant.CommonConstant.LoginType;
import com.datacvgproject.gsrobot.common.utils.HttpContextUtils;
import com.datacvgproject.gsrobot.common.utils.ResultMap;
import com.datacvgproject.gsrobot.modules.oauth.common.oauth2.OAuth2Token;
import com.google.gson.Gson;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
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;
public class AppOAuth2Filter extends AuthenticatingFilter {
@Override
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
String token = getRequestToken((HttpServletRequest) request);
if (StringUtils.isBlank(token)) {
return null;
}
return new OAuth2Token(token, LoginType.SYS.getType());
}
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
if (((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())) {
return true;
}
return false;
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
String token = getRequestToken((HttpServletRequest) request);
if (StringUtils.isBlank(token)) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
String json = new Gson().toJson(ResultMap.error(HttpStatus.SC_UNAUTHORIZED, "invalid token"));
httpResponse.getWriter().print(json);
return false;
}
return executeLogin(request, response);
}
@Override
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setContentType("application/json;charset=utf-8");
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
try {
Throwable throwable = e.getCause() == null ? e : e.getCause();
ResultMap resultMap = ResultMap.error(HttpStatus.SC_UNAUTHORIZED, throwable.getMessage());
String json = new Gson().toJson(resultMap);
httpResponse.getWriter().print(json);
} catch (IOException e1) {
}
return false;
}
private String getRequestToken(HttpServletRequest httpRequest) {
String token = httpRequest.getHeader("token");
if (StringUtils.isBlank(token)) {
token = httpRequest.getParameter("token");
}
return token;
}
}
认证
import com.datacvgproject.gsrobot.modules.console.pojo.entity.UserEntity;
import com.datacvgproject.gsrobot.modules.oauth.app.pojo.entity.AppUserTokenEntity;
import com.datacvgproject.gsrobot.modules.oauth.app.service.AppShiroService;
import com.datacvgproject.gsrobot.modules.oauth.common.enums.LockStatuEnum;
import com.datacvgproject.gsrobot.modules.oauth.common.oauth2.OAuth2Token;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Set;
@Component
public class AppOAuth2Realm extends AuthorizingRealm {
@Autowired
private AppShiroService appShiroService;
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof OAuth2Token;
}
@Override
public String getName() {
return "appUserRealm";
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
UserEntity user = (UserEntity) principals.getPrimaryPrincipal();
String userId = user.getUserId();
Set<String> permsSet = appShiroService.getAppUserPermissions(userId);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setStringPermissions(permsSet);
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String accessToken = (String) token.getPrincipal();
AppUserTokenEntity tokenEntity = appShiroService.queryByToken(accessToken);
if (tokenEntity == null || tokenEntity.getExpireTime().getTime() < System.currentTimeMillis()) {
throw new IncorrectCredentialsException("token失效,请重新登录");
}
UserEntity user = appShiroService.queryAppUser(tokenEntity.getUserId());
if (LockStatuEnum.LOCK.getStatu().equals(user.getLockStatus())) {
throw new LockedAccountException("账号已被锁定,请联系管理员");
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, accessToken, getName());
return info;
}
}