1.ShiroConfig.java 定义匿名用户可以访问的资源
filterMap.put("/webjars/**", "anon");
filterMap.put("/druid/**", "anon");
filterMap.put("/api/**", "anon");
filterMap.put("/sys/login", "anon");
filterMap.put("/**/*.css", "anon");
filterMap.put("/**/*.js", "anon");
filterMap.put("/**/*.html", "anon");
filterMap.put("/fonts/**", "anon");
filterMap.put("/plugins/**", "anon");
filterMap.put("/swagger/**", "anon");
filterMap.put("/favicon.ico", "anon");
filterMap.put("/", "anon");
filterMap.put("/**", "oauth2"); --除了anon,拦截其他所有请求
2.OAuth2Filter.java 基于shiro的全局过滤器
继承AuthenticatingFilter 实现createToken、isAccessAllowed、onAccessDenied、onLoginFailure等抽象方法
@Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { String token = getRequestToken((HttpServletRequest) request); if(StringUtils.isBlank(token)){ HttpServletResponse httpResponse = (HttpServletResponse) response; String json = new Gson().toJson(R.error(HttpStatus.SC_UNAUTHORIZED, "invalid token")); httpResponse.getWriter().print(json); return false; } System.out.println("onAccessDenied-----------------------onAccessDenied"); return executeLogin(request, response); }
如果成功获得token 则继续调用父类中executeLogin方法,此方法实现如下
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception { AuthenticationToken token = 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); } try { Subject subject = getSubject(request, response); subject.login(token); return onLoginSuccess(token, subject, request, response); } catch (AuthenticationException e) { return onLoginFailure(token, e, request, response); } }
调用子类中的createToken方法获得token对象,将token对象赋值给shiro subject 对象,从而在后面的认证方法中获得token
3.将OAuth2Realm 注册到Shiro Seurity中,ShiroConfig.securityManager
1 package io.renren.config; 2 3 import io.renren.modules.sys.oauth2.OAuth2Filter; 4 import io.renren.modules.sys.oauth2.OAuth2Realm; 5 import org.apache.shiro.mgt.SecurityManager; 6 import org.apache.shiro.session.mgt.SessionManager; 7 import org.apache.shiro.spring.LifecycleBeanPostProcessor; 8 import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; 9 import org.apache.shiro.spring.web.ShiroFilterFactoryBean; 10 import org.apache.shiro.web.mgt.DefaultWebSecurityManager; 11 import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; 12 import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; 13 import org.springframework.context.annotation.Bean; 14 import org.springframework.context.annotation.Configuration; 15 16 import javax.servlet.Filter; 17 import java.util.HashMap; 18 import java.util.LinkedHashMap; 19 import java.util.Map; 20 21 22 @Configuration 23 public class ShiroConfig { 24 25 @Bean("sessionManager") 26 public SessionManager sessionManager(){ 27 DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); 28 sessionManager.setSessionValidationSchedulerEnabled(true); 29 sessionManager.setSessionIdCookieEnabled(false); 30 System.out.println("获得sessionManager:" + sessionManager); 31 return sessionManager; 32 } 33 34 @Bean("securityManager") 35 public SecurityManager securityManager(OAuth2Realm oAuth2Realm, SessionManager sessionManager) { 36 DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); 37 securityManager.setRealm(oAuth2Realm); 38 securityManager.setSessionManager(sessionManager); 39 System.out.println("获得SecurityManager:" + securityManager); 40 return securityManager; 41 } 42 43 @Bean("shiroFilter") 44 public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) { 45 ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); 46 shiroFilter.setSecurityManager(securityManager); 47 48 //oauth过滤 49 Map<String, Filter> filters = new HashMap<>(); 50 filters.put("oauth2", new OAuth2Filter()); 51 shiroFilter.setFilters(filters); 52 53 Map<String, String> filterMap = new LinkedHashMap<>(); 54 filterMap.put("/webjars/**", "anon"); 55 filterMap.put("/druid/**", "anon"); 56 filterMap.put("/api/**", "anon"); 57 filterMap.put("/sys/login", "anon"); 58 filterMap.put("/**/*.css", "anon"); 59 filterMap.put("/**/*.js", "anon"); 60 filterMap.put("/**/*.html", "anon"); 61 filterMap.put("/fonts/**", "anon"); 62 filterMap.put("/plugins/**", "anon"); 63 filterMap.put("/swagger/**", "anon"); 64 filterMap.put("/favicon.ico", "anon"); 65 filterMap.put("/", "anon"); 66 filterMap.put("/**", "oauth2"); 67 shiroFilter.setFilterChainDefinitionMap(filterMap); 68 System.out.println("获得shiroFilter:" + shiroFilter); 69 return shiroFilter; 70 } 71 72 @Bean("lifecycleBeanPostProcessor") 73 public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { 74 return new LifecycleBeanPostProcessor(); 75 } 76 77 @Bean 78 public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { 79 DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator(); 80 proxyCreator.setProxyTargetClass(true); 81 return proxyCreator; 82 } 83 84 @Bean 85 public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { 86 AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); 87 advisor.setSecurityManager(securityManager); 88 return advisor; 89 } 90 91 }
4.每次请求都会先调用OAuth2Realm中的doGetAuthenticationInfo方法验证token的合法性,然后再调用doGetAuthorizationInfo验证权限
5.通过common.js判断当前客户端是否缓存了token,如果没有则跳转至login.html
//登录token
var token = localStorage.getItem("token");
if(token == ‘null‘){
parent.location.href = baseURL + ‘login.html‘;
}
6.登入页面输入用户名、密码之后 缓存token,并跳转至index.html
login: function () { var data = "username="+vm.username+"&password="+vm.password; $.ajax({ type: "POST", url: baseURL + "sys/login", data: data, dataType: "json", success: function(r){ if(r.code == 0){//登录成功 localStorage.setItem("token", r.token); parent.location.href =‘index.html‘; }else{ vm.error = true; vm.errorMsg = r.msg; } } }); }