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


基于引用内容和,可以解释shiro oauth2的工作原理。shiro oauth2是一种基于OAuth2协议的认证和授权框架。在shiro oauth2中,客户端应用首先向认证服务器申请令牌,包括第三方用户信息和用户请求信息。认证服务器会根据客户端应用的信息以及存储的第三方应用信息,生成Oauth2Authentication并创建Oatuth2AccessToken令牌。然后,TokenStore将令牌存储到指定的存储器中。 在资源服务器端,客户端携带令牌发送请求到达Oauth2AuthenticationProcessFilter。这个过程中,tokenExtractor会从请求中获取Authentication信息。OAuth2AuthenticationManager会通过tokenService查询token对应的OAuth2Authentication。如果登陆成功,Authentication会被放到SpringSecurityConetxt中。 基于引用内容,shiro oauth2还需要在配置文件中配置客户端的信息。这些信息包括clientId、clientSecret、accessTokenUri、userAuthorizationUri和userInfoUri等。 总结起来,shiro oauth2是通过OAuth2协议实现的一种认证和授权框架,它包括申请令牌的流程和验证令牌的流程。在使用shiro oauth2时,需要配置客户端的信息,并且可以使用TokenStore将令牌存储到指定的存储器中。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [SpringSecurity、ShiroOauth2.0、Cas](https://blog.csdn.net/m0_37695902/article/details/117596437)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [【开发技术】2万字分析shiro、spring security两大安全框架,spring session,OAuth2 入门级教程](https://blog.csdn.net/a23452/article/details/125967279)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值