Shiro認證-初學(二)
阿新 • • 發佈:2018-12-18
1:前後端分離:更改以前的ajax請求,由於目前的專案基本上都是前後端分離的,所以我們所有的資料都已JSON格式返回給前端,對沒有登入的請求進行攔截,覆蓋掉shiro原本的跳轉到login.jsp頁面,繼承FormAuthenticationFilter
public class AjaxPermissionsAuthorizationFilter extends FormAuthenticationFilter { @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { JSONObject jsonObject = new JSONObject(); jsonObject.put("returnCode", ErrorEnum.E_20011.getErrorCode()); jsonObject.put("returnMsg", ErrorEnum.E_20011.getErrorMsg()); PrintWriter out = null; HttpServletResponse res = (HttpServletResponse) response; try { res.setCharacterEncoding("UTF-8"); res.setContentType("application/json"); out = response.getWriter(); out.println(jsonObject); } catch (Exception e) { } finally { if (null != out) { out.flush(); out.close(); } } return false; } @Bean public FilterRegistrationBean registration(AjaxPermissionsAuthorizationFilter filter) { FilterRegistrationBean registration = new FilterRegistrationBean(filter); registration.setEnabled(false); return registration; } }
2:自定義Realm,重寫兩個介面方法,doGetAuthenticationInfo(登入)和doGetAuthorizationInfo(授權)
登入:拿資料匹配,查詢資料庫通過,建立SimpleAuthenticationInfo物件傳入使用者名稱和密碼,呼叫SecurityUtils.getSubject().getSession.setAttribute()存session
授權:呼叫SecurityUtils.getSubject.getSession()獲取session,從session中獲取到使用者的許可權,構建SimpleAuthorizationInfo物件,授權方法addStringPermissions()方法進行授權
public class UserRealm extends AuthorizingRealm { Logger logger= LoggerFactory.getLogger("UserRealm"); @Autowired private LoginService loginService; /** * 授權 * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { Session session=SecurityUtils.getSubject().getSession(); JSONObject perssions= (JSONObject) session.getAttribute(Constants.SESSION_USER_PERMISSION); logger.info("使用者的permissions:"+perssions); logger.info("使用者的許可權為:"+perssions.get("permissionList")); SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo(); simpleAuthorizationInfo.addStringPermissions((Collection<String>) perssions.get("perssionList")); return simpleAuthorizationInfo; } /** * 登入 * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { String loginName= (String) authenticationToken.getPrincipal(); String password= (String) authenticationToken.getCredentials(); JSONObject user=loginService.getUser(loginName,password); if(user==null){ //使用者不存在 throw new UnknownAccountException(); } //使用者存在 SimpleAuthenticationInfo authenticationInfo=new SimpleAuthenticationInfo( user.getString("username"), user.getString("password"), getName()); user.remove("password"); //將使用者資訊放入session中 SecurityUtils.getSubject().getSession().setAttribute(Constants.SESSION_USER_INFO,user); return authenticationInfo; } }
Shiro配置類:自定義shiro的過濾器鏈 Map結構
anon:他對應過濾器鏈裡面是空的,不用做什麼操作
authc:必須授權認證後的接口才可以訪問,他是Shiro內建的一個攔截器FormAuthenFilter
@Configuration
public class ShiroConfiguration {
private Logger logger= LoggerFactory.getLogger("ShiroConfiguration");
/**
* 全場最重要的一步shiro的web過濾器Factory
* 自定義Shiro過濾鏈,Map結構
* Map中key(xml中是指value值)的第一個'/'代表的路徑是相對於HttpServletRequest.getContextPath()的值來的
* anon:它對應的過濾器裡面是空的,什麼都沒做,這裡.do和.jsp後面的*表示引數,比方說login.jsp?main這種
* authc:該過濾器下的頁面必須驗證後才能訪問,它是Shiro內建的一個攔截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter
*/
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
//shiro的安全介面
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String,Filter> filterMap=new LinkedHashMap<>();
//此處為自定義ajax
filterMap.put("authc", new AjaxPermissionsAuthorizationFilter());
shiroFilterFactoryBean.setFilters(filterMap);
Map<String,String> filterChainDefinitionMap=new LinkedHashMap<>();
/**
*過濾鏈定義,從上向下順序執行,一般將 / ** 放在最為下邊:這是一個坑呢,一不小心程式碼就不好使了;
*authc:所有url都必須認證通過才可以訪問; anon:所有url都都可以匿名訪問
*/
filterChainDefinitionMap.put("/", "anon");
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/login/auth", "anon");
filterChainDefinitionMap.put("/login/logout", "anon");
filterChainDefinitionMap.put("/error", "anon");
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
//第一步
/**
* 不指定名字的話,自動建立一個方法名第一個字母小寫的bean
*/
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm());
return securityManager;
}
/**
* Shiro Realm 繼承自AuthorizingRealm的自定義Realm,即指定Shiro驗證使用者登入的類為自定義的
*/
@Bean
public UserRealm userRealm() {
UserRealm userRealm = new UserRealm();
return userRealm;
}
/**
* 第四部:憑證匹配器
*/
@Bean(name = "credentialsMatcher")
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//雜湊演算法:這裡使用MD5演算法;
hashedCredentialsMatcher.setHashAlgorithmName("md5");
//雜湊的次數,比如雜湊兩次,相當於 md5(md5(""));
hashedCredentialsMatcher.setHashIterations(2);
//storedCredentialsHexEncoded預設是true,此時用的是密碼加密用的是Hex編碼;false時用Base64編碼
hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
return hashedCredentialsMatcher;
}
/**
* 第三步,管理shiro的生命週期
*/
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**第二步:開啟Shiro註解(如@RequiresRoles,@RequiresPerssions,
* 藉助SpringAOP掃描使用Shiro註解的類
*/
@Bean
@DependsOn({"lifecycleBeanPostProcessor"})
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor;
}
}