用于保护 REST api 的 Apache Shiro

Posted

技术标签:

【中文标题】用于保护 REST api 的 Apache Shiro【英文标题】:Apache Shiro for securing REST api 【发布时间】:2013-05-24 03:09:31 【问题描述】:

我正在尝试将 Shiro 集成到我的 spring mvc 应用程序中。 身份验证由 LDAP 服务器支持,我能够成功地对 ldap 服务器进行身份验证并获取 cookie。

我无法执行的是在后续请求中使用此 cookie 并获得结果。尝试使用 cookie 会给我一个 HTTP 302 来再次执行身份验证。例如: GET on (rest/assets/list),标头 Cookie: JSESSIONID=abcd 重定向到 (rest/login)

这是保护 api 的正确策略吗? AngularJS 应用程序正在使用该 api,我希望在添加 CRUD 功能之前启用基于用户组的身份验证。

任何指针都会很有用。

源码如下:

applicationContext.xml文件如下

 <beans xmlns="http://www.springframework.org/schema/beans"
   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">


<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"/>

<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/>

<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
    <property name="securityManager" ref="securityManager"/>
</bean>

<bean id="ldapRealm" class="com.directv.nmsupport.security.LDAPRealm">
    <property name="contextFactory" ref="ldapContextFactory" />
    <property name="userDnTemplate" value="uid=0,ou=DirecTV,ou=People,dc=swengdtv,dc=net" />
</bean>

<bean id="ldapContextFactory" class="org.apache.shiro.realm.ldap.JndiLdapContextFactory">
    <property name="url" value="ldap://teon:389"/>
</bean>

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="realm" ref="ldapRealm"/>
    <property name="cacheManager" ref="cacheManager"/>
    <property name="sessionManager" ref="sessionManager" />
</bean>

<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
    <property name="sessionIdCookieEnabled" value="true" />
</bean>

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager"/>
    <property name="loginUrl" value="/rest/login"/>
    <property name="filterChainDefinitions">
        <value>
            /rest/login = anon
            /rest/** = user
        </value>
    </property>
</bean>
</beans>

LDAPRealm.java 代码是

public class LDAPRealm extends JndiLdapRealm 

@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) 
    String username = (String) getAvailablePrincipal(principals);
    return super.doGetAuthorizationInfo(principals);    //To change body of overridden methods use File | Settings | File Templates.


@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException 
    return super.doGetAuthenticationInfo(token);    //To change body of overridden methods use File | Settings | File Templates.

LoginController.java 是

@Controller
public class LoginController 

@RequestMapping(value = "/login", method = RequestMethod.POST)
public void login(@RequestBody UserCredentials user) 
    UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
    token.setRememberMe(true);
    SecurityUtils.getSecurityManager().authenticate(token);
    Subject subject = SecurityUtils.getSubject();
    subject.getSession(true);


@RequestMapping(value="/logout")
public void logout() 
    Subject subject = SecurityUtils.getSubject();
    SecurityUtils.getSecurityManager().logout(subject);

apache shiro 的日志记录是

17:47:54.428 ["http-bio-8080"-exec-7] DEBUG o.a.shiro.realm.ldap.JndiLdapRealm - Authenticating user 'afulara' through LDAP
17:47:54.428 ["http-bio-8080"-exec-7] DEBUG o.a.s.r.ldap.JndiLdapContextFactory - Initializing LDAP context using URL [ldap://teon:389] and principal [uid=afulara,ou=DirecTV,ou=People,dc=swengdtv,dc=net] with pooling disabled
17:47:54.431 ["http-bio-8080"-exec-7] DEBUG o.a.shiro.realm.AuthenticatingRealm - Looked up AuthenticationInfo [afulara] from doGetAuthenticationInfo
17:47:54.431 ["http-bio-8080"-exec-7] DEBUG o.a.shiro.realm.AuthenticatingRealm - AuthenticationInfo caching is disabled for info [afulara].  Submitted token: [org.apache.shiro.authc.UsernamePasswordToken - afulara, rememberMe=true].
17:47:54.431 ["http-bio-8080"-exec-7] DEBUG o.a.s.authc.AbstractAuthenticator - Authentication successful for token [org.apache.shiro.authc.UsernamePasswordToken - afulara, rememberMe=true].  Returned account [afulara]
17:48:20.927 ["http-bio-8080"-exec-9] DEBUG o.a.shiro.web.servlet.SimpleCookie - Found 'JSESSIONID' cookie value [02b41ee8-e9e3-43e5-8ee3-aae72322fede]
17:48:24.204 ["http-bio-8080"-exec-10] DEBUG o.a.shiro.web.servlet.SimpleCookie - Found 'JSESSIONID' cookie value [02b41ee8-e9e3-43e5-8ee3-aae72322fede]
17:48:24.210 ["http-bio-8080"-exec-10] WARN  o.s.web.servlet.PageNotFound - Request method 'GET' not supported

【问题讨论】:

跟进。我从来没有得到这个工作并切换到 Spring Security 并发现它得到了更多的支持(通过社区和谷歌搜索)并完成了这个活动。 然后使用“回答你自己的问题”功能。这样人们就可以很快知道您的问题已经解决了。 我认为这不是正确的策略。根据 REST 原则,您不得创建与客户端的会话。保护 REST api 的更好方法是 Basic AuthenticationOAuth 【参考方案1】:

由于人们要求我将我的答案作为单独的答案发布,所以就在这里。

我没有使用 Apache Shiro。

PS:并不是说 Apache shiro 不好。我刚刚发现 Spring Security 更容易满足我的特定需求。 YMMV

【讨论】:

【参考方案2】:

REST 背后的理念是它是无状态的,因此,如果您与客户端创建会话,您将打破 RESTful API 的原则。我建议使用 Spring Security,你可以在这里找到一个简单的例子:http://spring.io/guides/gs/securing-web/。大约需要 5 到 10 分钟,然后您就可以在项目中使用它了。

还有一个连接到 LDAP 系统的简单指南: http://spring.io/guides/gs/authenticating-ldap/

更新:看到你对你的问题的评论,我建议你用你想出的结果来回答你的问题。

【讨论】:

以上是关于用于保护 REST api 的 Apache Shiro的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 REST + CodeceptJS 测试 API,访问受 Auth0 保护?

使用 AWS Cognito 保护 REST API

如何使用 Keycloak 保护前端和 REST API

使用 OAuth2 保护单体私有 REST api? [关闭]

使用 OAuth2 客户端凭据流保护用 PHP 编写的 REST API

如何保护移动应用程序的 API REST? (如果嗅探请求给了你“钥匙”)