Web 应用程序 Apache Shiro 集成

Posted

技术标签:

【中文标题】Web 应用程序 Apache Shiro 集成【英文标题】:Web application Apache Shiro integration 【发布时间】:2015-05-15 03:02:52 【问题描述】:

我正在尝试了解 Apache Shiro 工作流程以及如何将其集成到我的应用程序中。我无法理解的是我如何以及在哪里执行登录然后发送重定向?还是 Shiro 会自动执行此操作(因为我在 ini 文件中指定了领域)?我可以将自定义信息(用户属性)与重定向一起发送(通过 Servlet 响应而不是支持 bean)吗?

到目前为止我所了解和拥有的:

将 Shiro 侦听器和过滤器添加到 web.xml 文件中,以便它可以响应请求:

<listener>
    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>

<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

创建一个 shiro.ini 文件,您可以在其中为 Shiro 配置一些属性:

[main]
shiro.loginURL = /login.xhtml
myRealm = com.example.shiro.MyRealm
securityManager.realms = $myRealm

[urls]
/account/** = authc
/logout = logout

创建自定义领域类:

@Stateless
@Local(Realm.class)
public class SecurityBean implements Realm
    private EntityManager em;
    private TypedQuery<Credential> cQuery;

    @Override
    public Account getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException 
        try
            cQuery = em.createNamedQuery("getCredentials", Credential.class);
            cQuery.setParameter("userName", ((UsernamePasswordToken) token).getUsername());
            Credential c = cQuery.getSingleResult();
            boolean b = Encryption.compare(new String(((UsernamePasswordToken) token).getPassword()), c.getSalt(), c.getEncryptedPassword());
            if(b)
                return c;
            else
                throw new AuthenticationException("Passwords do not match.");
            
        catch(Exception e)
            throw new AuthenticationException("Error verifying credentials.");
        
    

    @Override
    public String getName() 
        return "User Realm";
    

    @Override
    public boolean supports(AuthenticationToken token) 
        if(token instanceof UsernamePasswordToken)
            return true;
        else
            return false;
        
    

其中 Encryption 是用于加密和比较密码的类,Credential 是用于存储用户名和密码的 JPA Entity 类:

@NamedQueries(@NamedQuery(name = "getCredentials", query = "SELECT c FROM Credential c WHERE c.userName = :userName"),
            @NamedQuery(name = "deleteCredentials", query = "DELETE FROM Credential c WHERE c.userName = :userName"))
@Entity
public class Credential implements Serializable, Account
    private static final long serialVersionUID = 2555682746921997545L;

    @Id @GeneratedValue
    private long id;

    private String userName;

    private String encryptedPassword;
    private String salt;

    private User user;

    //... getters/setters...

其中 User 是一个 JPA 实体类,它实际存储用户的应用程序信息。

【问题讨论】:

【参考方案1】:

Shiro 将自动拦截对受限资源的任何请求,并显示定义的登录屏幕。您只需要声明您的应用资源所需的身份验证级别。获取您的代码:

[main]
shiro.loginURL = /login.xhtml
myRealm = com.example.shiro.MyRealm
securityManager.realms = $myRealm

[urls]
/account/** = authc
/logout = logout

你是在告诉白:

    向用户显示的登录屏幕是/login.xhtml 您的Realm 班级是com.example.shiro.MyRealm。 Shiro 将对其进行实例化,并将特定于应用程序的安全操作委托给它。您可以在此处编写特定的安全代码。如果我没有理解错,您的SecurityBean 是您的自定义Realm,因此它应该重命名为com.example.shiro.MyRealm,或者您将myRealm 更改为指向该类。 /account/** = authc/account/ 中的每个资源都需要对用户进行身份验证。因此,如果用户尚未通过身份验证,任何尝试去那里都会导致 Shiro 显示登录页面。 当用户转到/logout时,shiro 将结束会话

我看到的是您在[urls] 部分的开头缺少这一行:/login.xhtml = authc/login.xhtml 不限于经过身份验证的用户(否则没有人可以登录),但仍必须为其指定 authc 过滤器,以便它可以处理该 url 的登录提交。它足够“智能”以允许这些请求通过 shiro.loginUrl 以上。

顺便说一句,如果您还想拥有完整的用户管理解决方案,请查看Stormpath。我们还有一个plugin 可以与 Shiro 无缝协作。您可以查看我们的示例Stormpath Shiro app

免责声明,我是 Stormpath 的活跃贡献者。

【讨论】:

以上是关于Web 应用程序 Apache Shiro 集成的主要内容,如果未能解决你的问题,请参考以下文章

使用 Apache Shiro 在自定义 Java Web 应用程序与 Drupal 之间进行 SSO 集成

Apache Shiro Web应用整合-配置

Apache Shiro 的Web应用支持指南

在 Web 项目中应用 Apache Shiro

Shiro简介入门案例web容器的集成

Shiro集成web环境[Springboot]-基础使用