shiro oauth2 调用逻辑
本文也是拿来主义,拿别人的代码跑了一遍,算是自己的理解吧
主要两块:
auth-client 客户端(第三方应用)
auth-web(内部依赖auth-server) 服务提供方(这里资源和认证放在一起了,一般认证是独立的)
auth-client的shiro配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!-- 缓存管理器 --> <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:ehcache/ehcache.xml"/> </bean> <!-- Realm实现 --> <bean id="oAuth2Realm" class="com.hjzgg.auth.client.shiro.OAuth2Realm"> <property name="cachingEnabled" value="true"/> <property name="authenticationCachingEnabled" value="true"/> <property name="authenticationCacheName" value="authenticationCache"/> <property name="authorizationCachingEnabled" value="true"/> <property name="authorizationCacheName" value="authorizationCache"/> <property name="clientId" value="c1ebe466-1cdc-4bd3-ab69-77c3561b9dee"/> <property name="clientSecret" value="d8346ea2-6017-43ed-ad68-19c0f971738b"/> <property name="accessTokenUrl" value="http://127.0.0.1:8080/auth-web/oauth/accessToken"/> <property name="userInfoUrl" value="http://127.0.0.1:8080/auth-web/oauth/userInfo"/> <property name="redirectUrl" value="http://127.0.0.1:8080/auth-client/login"/> </bean> <!-- 会话ID生成器 --> <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/> <!-- 会话Cookie模板 --> <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="sid"/> <property name="httpOnly" value="true"/> <property name="maxAge" value="-1"/> </bean> <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="rememberMe"/> <property name="httpOnly" value="true"/> <property name="maxAge" value="2592000"/><!-- 30天 --> </bean> <!-- rememberMe管理器 --> <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager"> <!-- rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)--> <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode("4AvVhmFLUs0KTA3Kprsdag==")}"/> <property name="cookie" ref="rememberMeCookie"/> </bean> <!-- 会话DAO --> <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"> <property name="activeSessionsCacheName" value="shiro-activeSessionCache"/> <property name="sessionIdGenerator" ref="sessionIdGenerator"/> </bean> <!-- 会话管理器 --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <property name="globalSessionTimeout" value="1800000"/> <property name="deleteInvalidSessions" value="true"/> <property name="sessionValidationSchedulerEnabled" value="true"/> <property name="sessionDAO" ref="sessionDAO"/> <property name="sessionIdCookieEnabled" value="true"/> <property name="sessionIdCookie" ref="sessionIdCookie"/> </bean> <!-- 安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="oAuth2Realm"/> <property name="sessionManager" ref="sessionManager"/> <property name="cacheManager" ref="cacheManager"/> <property name="rememberMeManager" ref="rememberMeManager"/> </bean> <!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) --> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/> <property name="arguments" ref="securityManager"/> </bean> <!-- OAuth2身份验证过滤器 --> <bean id="oAuth2AuthenticationFilter" class="com.hjzgg.auth.client.shiro.OAuth2AuthenticationFilter"> <property name="authcCodeParam" value="code"/> <property name="failureUrl" value="/oauth2Failure.jsp"/> </bean> <!-- Shiro的Web过滤器 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="loginUrl" value="http://127.0.0.1:8080/auth-web/oauth/authorize?client_id=c1ebe466-1cdc-4bd3-ab69-77c3561b9dee&response_type=code&redirect_uri=http://127.0.0.1:8080/auth-client/login"/> <property name="successUrl" value="/index.jsp"/> <property name="filters"> <util:map> <entry key="oauth2Authc" value-ref="oAuth2AuthenticationFilter"/> </util:map> </property> <property name="filterChainDefinitions"> <value> /oauth2Failure.jsp = anon /login = oauth2Authc /logout = logout /** = user </value> </property> </bean> <!-- Shiro生命周期处理器--> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> </beans>
auth-web的shiro配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!-- 缓存管理器 --> <bean id="cacheManager" class="com.hjzgg.auth.util.SpringCacheManagerWrapper"> <property name="cacheManager" ref="springCacheManager"/> </bean> <bean id="springCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"> <property name="cacheManager" ref="ehcacheManager"/> </bean> <!--ehcache--> <bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation" value="classpath:ehcache/ehcache.xml"/> </bean> <!-- 凭证匹配器 --> <bean id="credentialsMatcher" class="com.hjzgg.auth.shiro.RetryLimitHashedCredentialsMatcher"> <constructor-arg ref="cacheManager"/> <property name="hashAlgorithmName" value="md5"/> <property name="hashIterations" value="2"/> <property name="storedCredentialsHexEncoded" value="true"/> </bean> <!-- Realm实现 --> <bean id="userRealm" class="com.hjzgg.auth.shiro.UserRealm"> <!--<property name="credentialsMatcher" ref="credentialsMatcher"/>--> <property name="cachingEnabled" value="false"/> <!--<property name="authenticationCachingEnabled" value="true"/>--> <!--<property name="authenticationCacheName" value="authenticationCache"/>--> <!--<property name="authorizationCachingEnabled" value="true"/>--> <!--<property name="authorizationCacheName" value="authorizationCache"/>--> </bean> <!-- 会话ID生成器 --> <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/> <!-- 会话Cookie模板 --> <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="sid"/> <property name="httpOnly" value="true"/> <property name="maxAge" value="-1"/> </bean> <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="rememberMe"/> <property name="httpOnly" value="true"/> <property name="maxAge" value="2592000"/><!-- 30天 --> </bean> <!-- rememberMe管理器 --> <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager"> <!-- rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)--> <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode("4AvVhmFLUs0KTA3Kprsdag==")}"/> <property name="cookie" ref="rememberMeCookie"/> </bean> <!-- 会话DAO --> <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"> <property name="activeSessionsCacheName" value="shiro-activeSessionCache"/> <property name="sessionIdGenerator" ref="sessionIdGenerator"/> </bean> <!-- 会话管理器 --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <property name="globalSessionTimeout" value="1800000"/> <property name="deleteInvalidSessions" value="true"/> <property name="sessionValidationSchedulerEnabled" value="true"/> <property name="sessionDAO" ref="sessionDAO"/> <property name="sessionIdCookieEnabled" value="true"/> <property name="sessionIdCookie" ref="sessionIdCookie"/> </bean> <!-- 安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="userRealm"/> <property name="sessionManager" ref="sessionManager"/> <property name="cacheManager" ref="cacheManager"/> <property name="rememberMeManager" ref="rememberMeManager"/> </bean> <!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) --> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/> <property name="arguments" ref="securityManager"/> </bean> <bean name="formAuthenticationFilter" class="com.hjzgg.auth.shiro.FormAuthenticationFilter"/> <!-- Shiro的Web过滤器 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="filters"> <util:map> <entry key="authc" value-ref="formAuthenticationFilter"/> </util:map> </property> <property name="loginUrl" value="/login.jsp"/> <property name="successUrl" value="/index.jsp"/> <property name="filterChainDefinitions"> <value> /logout = logout /login.jsp = authc /oauth/authorize=anon /oauth/accessToken=anon /oauth/userInfo=anon /** = roles[admin] </value> </property> </bean> <!-- Shiro生命周期处理器--> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> </beans>
这里区别于常规shiro的主要逻辑是:
1. 将本地shiro的登录认证改为了认证服务器auth-web的地址
2. auth-web执行完回调auth-client提供的redirect_uri
3. auth-client通过redirect_uri被自己配置的oauth2Authc过滤器拦截
4. OAuth2AuthenticationFilter根据从认证服务器auth-web获取到的code进行executeLogin
5. login时是通过Oauth2Realm.doGetAuthenticationIfo进行,内部会调用auth-web生成token的uri进行获取token
6. 后面通过传递token获取auth-web的userInfo,生成authenticationInfo
下面稍微详细展开叙述
1. 访问127.0.0.1:8080/auth-client/
因为auth-client的shiro中配置的loginUrl配置的http://127.0.0.1:8080/auth-web/oauth/authorize*******
则进入到auth-web的authorize
authorize 主要是验证clientID 和 是否登录,因没有登录则跳转到自己的login.jsp
数组账号密码登录
则进入 FormAuthenticationFilter 父类AuthenticatingFilter的executeLogin
subject.login(token)后,会调用自己配置的UserRealm <bean id="userRealm" class="com.hjzgg.auth.shiro.UserRealm">
上面就是常规的shiro认证,完成后则会回调上次访问的url,及authorize
同时在authorize里面生成了code,就是授权码
后面就回调了auth-client传过来的redirectUri http://127.0.0.1:8080/auth-client/login
则被配置的oAuth2AuthenticationFilter拦截 进入父类的 executeLogin
subject.login 后 调用 自身配置的 <bean id="oAuth2Realm" class="com.hjzgg.auth.client.shiro.OAuth2Realm">
内部会调用 auth-web的accessToken获取token
改方法主要是先验证clientId,clientkey,authcode无误后生成token
获取token后,调用auth-web的userinfo 获取用户信息
用获取到的userinfo 进行后续的认证
至此,整个流程完成。
后续需要访问auth-web资源的,把token带上,即可访问。
另注意下 shiro 缓存配置
shiro主要使用AuthenticatingRealm 类进行认证,其中getAuthenticationInfo方法中使用了缓存。
在getAuthenticationInfo中,首先判断是否有缓存记录,没有的话,再调用子类Ream的doGetAuthenticationInfo方法查询数据库,
再将查询到数据缓存起来,下次就不用查询数据库。
<!-- Realm实现 --> <bean id="userRealm" class="com.hjzgg.auth.shiro.UserRealm"> <!--<property name="credentialsMatcher" ref="credentialsMatcher"/>--> <property name="cachingEnabled" value="true"/> <property name="authenticationCachingEnabled" value="true"/> <property name="authenticationCacheName" value="authenticationCache"/> <property name="authorizationCachingEnabled" value="true"/> <property name="authorizationCacheName" value="authorizationCache"/> </bean>AuthenticatingRealm
getCachedAuthenticationInfo
getAuthenticationCacheKey
UsernamePasswordToken
看完上面的,也就清晰的知道缓存时通过username区分的,我们也可以根据token 授权码之类的
所用到的源码:http://download.csdn.net/download/stonexmx/10126569
- 上一篇:没有了
- 下一篇:没有了