过滤器链条配置说明
1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过 3、部分过滤器可指定参数,如perms,roles
Shiro内置的FilterChain
anon(org.apache.shiro.web.filter.authc.AnonymousFilter):例子/admins/**=anon 没有参数,表示可以匿名使用。 authc(org.apache.shiro.web.filter.authc.FormAuthenticationFilter):例如/admins/user/**=authc表示需要认证(登录)才能使用,没有参数 authcBasic(org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter):例如/admins/user/**=authcBasic,没有参数表示httpBasic认证 perms org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter:(权限)例子/admins/user/=perms[user:add:],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/ =perms[“user:add:,user:modify:*”],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。 port org.apache.shiro.web.filter.authz.PortFilter:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString rest org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter:例子/admins/user/=rest[user],根据请求的方法,相当于/admins/user/ =perms[user:method] ,其中method为post,get,delete等。 roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter:(角色)例子/admins/user/=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/ =roles[“admin,guest”],每个参数通过才算通过,相当于hasAllRoles()方法。 ssl org.apache.shiro.web.filter.authz.SslFilter:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https user org.apache.shiro.web.filter.authc.UserFilter:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查
配置注意事项
/admin?=authc 表示可以请求以admin开头的字符串,如xxx/adminfefe,但无法匹配多个,即xxx/admindf/admin是不行的 /admin*=authc 表示可以匹配零个或者多个字符,如/admin,/admin1,/admin123,但是不能匹配/admin/abc这种 /admin/**=authc 表示可以匹配零个或者多个路径,如/admin,/admin/ad/adfdf等 /login=anon 不会对http://localhost:8080/login/ 起效果 /login=anon 和 /login=anon/ 不一样
自定义过滤器介绍
过滤器一般实现org.apache.shiro.web.filter.authc.AuthenticatingFilter类。 方法使用说明
package cn.xo68.boot.auth.server.shiro.filter;
import java.io.IOException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import cn.xo68.boot.auth.core.domain.OAuth2AuthenticationToken;
import cn.xo68.boot.auth.core.domain.Oauth2Principal;
import cn.xo68.boot.auth.core.properties.OAuthResourceProperties;
import cn.xo68.boot.auth.server.properties.AuthServerProperties;
import cn.xo68.core.util.StringTools;
import org.apache.oltu.oauth2.client.OAuthClient;
import org.apache.oltu.oauth2.client.URLConnectionClient;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
import org.apache.oltu.oauth2.client.response.OAuthAccessTokenResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.message.types.GrantType;
import org.apache.oltu.oauth2.common.message.types.ParameterStyle;
import org.apache.oltu.oauth2.rs.request.OAuthAccessResourceRequest;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ThreadContext;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.subject.WebSubject;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
/**
* oauth2 认证过滤器
* @author wuxie
* @date 2018-8-5
*/
public class OAuth2AuthenticationFilter extends AuthenticatingFilter {
private static final Logger logger= LoggerFactory.getLogger(OAuth2AuthenticationFilter.class);
private SimpleCookie accessTokenCookie;
private AuthServerProperties authServerProperties;
private OAuthResourceProperties oAuthResourceProperties;
private String authcCodeParam = "code" ;
private String clientId;
private String redirectUrl;
private String responseType = "code" ;
private String failureUrl;
public SimpleCookie getAccessTokenCookie () {
return accessTokenCookie;
}
public void setAccessTokenCookie (SimpleCookie accessTokenCookie) {
this .accessTokenCookie = accessTokenCookie;
}
public AuthServerProperties getAuthServerProperties () {
return authServerProperties;
}
public void setAuthServerProperties (AuthServerProperties authServerProperties) {
this .authServerProperties = authServerProperties;
}
public OAuthResourceProperties getoAuthResourceProperties () {
return oAuthResourceProperties;
}
public void setoAuthResourceProperties (OAuthResourceProperties oAuthResourceProperties) {
this .oAuthResourceProperties = oAuthResourceProperties;
}
public void setAuthcCodeParam (String authcCodeParam) {
this .authcCodeParam = authcCodeParam;
}
public void setClientId (String clientId) {
this .clientId = clientId;
}
public void setRedirectUrl (String redirectUrl) {
this .redirectUrl = redirectUrl;
}
public void setResponseType (String responseType) {
this .responseType = responseType;
}
public void setFailureUrl (String failureUrl) {
this .failureUrl = failureUrl;
}
/**
* 如命名字面意思,根据请求,生成一个令牌。OAuth2AuthenticationToken是我自定义的
*/
@Override
protected AuthenticationToken createToken (ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpRequest = (HttpServletRequest) request;
try {
OAuthAccessResourceRequest oauthRequest = new OAuthAccessResourceRequest(httpRequest, ParameterStyle.HEADER, ParameterStyle.QUERY);
OAuth2AuthenticationToken oAuth2AuthenticationToken=new OAuth2AuthenticationToken();
Oauth2Principal oauth2Principal=new Oauth2Principal();
oAuth2AuthenticationToken.setPrincipal(oauth2Principal);
String accessToken = oauthRequest.getAccessToken();
if (StringTools.isEmpty(accessToken)){
accessToken=accessTokenCookie.getValue();
}
if (StringTools.isNotEmpty(accessToken)){
oAuth2AuthenticationToken.setCredential(accessToken);
oauth2Principal.setAccessToken(accessToken);
return oAuth2AuthenticationToken;
}else {
String code = httpRequest.getParameter(authcCodeParam);
if (StringTools.isNotEmpty(code)){
OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
OAuthClientRequest accessTokenRequest = OAuthClientRequest
.tokenLocation(oAuthResourceProperties.getAccessTokenUrl())
.setGrantType(GrantType.AUTHORIZATION_CODE)
.setClientId(oAuthResourceProperties.getClientId())
.setClientSecret(oAuthResourceProperties.getClientSecret())
.setCode(code)
.setRedirectURI(redirectUrl)
.buildQueryMessage();
OAuthAccessTokenResponse oAuthResponse = oAuthClient.accessToken(accessTokenRequest, OAuth.HttpMethod.POST);
accessToken=oAuthResponse.getAccessToken();
oAuth2AuthenticationToken.setCredential(accessToken);
oauth2Principal.setAccessToken(accessToken);
return oAuth2AuthenticationToken;
}
}
}catch (OAuthProblemException e){
logger.warn("过滤器中获取令牌令牌异常" , e);
}
return new OAuth2AuthenticationToken();
}
/**
* 根据请求信息,参数等信息判断是否允许通过,如果返回false,则是不通过。最终是否去访问web处理,有isAccessAllowed,onAccessDenied方法共同或运算决定,也就是只要有一个是true就会访问web控制器或action。
*/
@Override
protected boolean isAccessAllowed (ServletRequest request, ServletResponse response, Object mappedValue) {
return false ;
}
/**
*根据请求,拒绝通过处理,如果返回false,则不再去访问web控制器或action
*/
@Override
protected boolean onAccessDenied (ServletRequest request, ServletResponse response) throws Exception {
String error = request.getParameter("error" );
String errorDescription = request.getParameter("error_description" );
if (!StringUtils.isEmpty(error)) {
WebUtils.issueRedirect(request, response, authServerProperties.getUnauthorizedUrl() + "?error=" + error + "error_description=" + errorDescription);
return false ;
}
return executeLogin(request, response);
}
/**
* 登录验证处理,父类本来就有,只是有个bug,按官方给出的方法进行了重写
*/
@Override
protected boolean executeLogin (ServletRequest request, ServletResponse response) throws Exception {
AuthenticationToken token = this .createToken(request, response);
if (token == null ) {
String msg = "createToken method implementation returned null. A valid non-null AuthenticationToken must be created in order to execute a login attempt." ;
throw new IllegalStateException(msg);
} else {
try {
Subject subject = new WebSubject.Builder(request, response).buildSubject();
subject.login(token);
ThreadContext.bind(subject);
return this .onLoginSuccess(token, subject, request, response);
} catch (AuthenticationException var5) {
return this .onLoginFailure(token, var5, request, response);
}
}
}
@Override
protected boolean onLoginSuccess (AuthenticationToken token, Subject subject, ServletRequest request,
ServletResponse response) throws Exception {
Subject msubject=subject;
return true ;
}
/**
*登录失败处理(认证令牌验证失败)
*/
@Override
protected boolean onLoginFailure (AuthenticationToken token, AuthenticationException ae, ServletRequest request,
ServletResponse response) {
Subject subject = getSubject(request, response);
if (subject.isAuthenticated() || subject.isRemembered()) {
try {
issueSuccessRedirect(request, response);
} catch (Exception e) {
e.printStackTrace();
}
} else {
try {
WebUtils.issueRedirect(request, response, authServerProperties.getUnauthorizedUrl());
} catch (IOException e) {
e.printStackTrace();
}
}
return false ;
}
}