微信公眾號(hào)授權(quán)與Shiro權(quán)限框架整合
背景
微信公眾號(hào)授權(quán)之后贮配,想訪問本地服務(wù)器的資源停蕉。
實(shí)現(xiàn)
-
創(chuàng)建新的Token類型。Shiro默認(rèn)用的Token類型是UsernamePasswordToken,仿照UsernamePasswordToken震庭,建一個(gè)屬于微信用戶的Token類型蝴韭,叫MockToke
private String username; //用戶名 public String getUsername() { return this.username; } public void setUsername(String username) { this.username = username; } @Override public Object getPrincipal() { return this.username; } @Override public Object getCredentials() { return null; //密碼返回null,不進(jìn)行認(rèn)證 }
-
添加filter類,來處理不同類型的請(qǐng)求到不同的登陸頁面
//表明是訪問微信資源的請(qǐng)求,省略set方法 private String urlPattern; //微信請(qǐng)求對(duì)應(yīng)跳轉(zhuǎn)頁面,省略set方法 private String wxloginUrl; //未登錄重定向到登陸頁 @Override protected void redirectToLogin(ServletRequest req, ServletResponse resp) throws IOException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; String loginUrl; //后臺(tái)地址跳轉(zhuǎn)到后臺(tái)登錄地址抛猖,前臺(tái)需要登錄的跳轉(zhuǎn)到shiro配置的登錄地址 //若請(qǐng)求里包含urlPattern茎匠,設(shè)置loginUrl為微信登錄授權(quán)頁入口 if (request.getRequestURI().indexOf(getUrlPattern())!=-1) { loginUrl = getWxloginUrl(); } else { loginUrl = getLoginUrl(); } WebUtils.issueRedirect(request, response, loginUrl); }
修改Shiro配置文件忘瓦,添加Filters
//添加filter的bean搁廓,初始化參數(shù)值。
<bean id="userFilter" class="com.smallchill.core.filter.WltxUserFilter">
<property name="urlPattern" value="/wx"/>
<property name="wxloginUrl" value="https://open.weixin.qq.com/connect/oauth2/authorize?appid=YOU_APP_ID&redirect_uri=http%3A%2F%2Fwltx.wx.tunnel.echomod.cn%2FWxAuthServlet&response_type=code&scope=snsapi_userinfo&state=STATE&connect_redirect=1#wechat_redirect"/>
</bean>
shiroFilter配置中添加filter
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 安全管理器 -->
<property name="securityManager" ref="securityManager" />
<!-- 默認(rèn)的登陸訪問url -->
<property name="loginUrl" value="/login" />
<!-- 登陸成功后跳轉(zhuǎn)的url -->
<property name="successUrl" value="/" />
<!-- 沒有權(quán)限跳轉(zhuǎn)的url -->
<property name="unauthorizedUrl" value="/unauth" />
<!-- 作用于rest無狀態(tài)的api過濾器 -->
<property name="filters">
<map>
<!--<entry key="rest" >
<bean id="restShiroFilter" class="com.smallchill.core.shiro.RestAuthorizationFilter"></bean>
</entry>-->
<entry key="user" value-ref="userFilter" />
</map>
</property>
<property name="filterChainDefinitions">
<value>
<!--
anon 不需要認(rèn)證
authc 需要認(rèn)證
user 驗(yàn)證通過或RememberMe登錄的都可以
rest 用于rest無狀態(tài)服務(wù)
-->
/static/** = anon
/wx/** = user
/WxAuthServlet = anon <!-- 微信授權(quán)完耕皮,redirect跳轉(zhuǎn)路徑境蜕,因此時(shí)還沒拿到微信用戶信息,設(shè)置為不需要認(rèn)證 -->
/MP_verify_LAdRmyUraSqTJfHH.txt = anon
/login = anon
/WxServlet = anon
/captcha = anon
/** = user
</value>
</property>
</bean>
-
修改Realm類用戶驗(yàn)證方法凌停,若為微信用戶粱年,免密碼驗(yàn)證
/** * 登錄認(rèn)證 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { log.info("Shiro登錄認(rèn)證啟動(dòng)"); //若為微信用戶token if(authcToken instanceof MockToken){ SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(authcToken.getPrincipal(),null,getName()); return info; } IShiro shiroFactory = ShiroManager.me().getDefaultShiroFactory(); UsernamePasswordToken token = (UsernamePasswordToken) authcToken; User user = shiroFactory.user(token.getUsername()); ShiroUser shiroUser = shiroFactory.shiroUser(user); SimpleAuthenticationInfo info = shiroFactory.info(shiroUser, user, getName()); log.info("Shiro登錄認(rèn)證完畢"); return info; }
重寫Realm的supports方法,使之支持MockToken
@Override public boolean supports(AuthenticationToken token) { return token instanceof UsernamePasswordToken || token instanceof MockToken; }
-
微信授權(quán)通過后罚拟,redirect到配置的路徑台诗,獲取微信用戶信息,緩存用戶信息赐俗,登陸拉队。 以下為WxAuthServlet的部分代碼
WxUserInfo userInfo = wxAdapter.getWxUserInfo(accessToken,openId); // 設(shè)置要傳遞的參數(shù) WxUserCatch.catchUserInfo(userInfo); MockToken token = new MockToken(); token.setRememberMe(true); token.setUsername(userInfo.getOpenId()); Subject currentUser = ShiroKit.getSubject(); currentUser.login(token); // 跳轉(zhuǎn)到index.html request.getRequestDispatcher("/wx/index.html").forward(request, response);