如何面向接口编程以及读acegi框架有感

首先acegi框架是什么,它是一个权限框架.很多人不知道,我一说spring-security很多人就知道。

acegi框架是spring-security的前身,后面随着版本演化更名为spring-security的。

为什么不直接读spring-security源码读acegi源码,因为框架随着时间推移,抽象程度更高,不容易体会思想,

一旦领会了思想,那么框架后面的更新只是更加抽象而已,本质上换汤不换药。我选取的是acegi-security-1.0.4版本进行研究的,

这个版本网上很难找到,CSDN可以找到,需要积分,如有需要,评论留下邮箱,我会发过去。

我们首先谈一个问题,不用框架怎么写一个权限控制框架,很多人说这很简单.基于RBAC原则设计权限 角色 用户等表以及关联表即可实现,表查询即可。是的,是很简单,但是写出来的代码是否高度封装,高度抽象,就不简单。比如说用户对象怎么定义,很多人不会基于面向接口的思维去开发的,直接一上来就写了一个user对象 里面放入username password等字段,我们来看看acegi框架是怎么处理的

首先框架先定义个UserDetails接口

/**
 * Provides core user information.
 *
 * <p>
 * Implementations are not used directly by Acegi Security for security
 * purposes. They simply store user information which is later encapsulated
 * into {@link Authentication} objects. This allows non-security related user
 * information (such as email addresses, telephone numbers etc) to be stored
 * in a convenient location.
 * </p>
 *
 * <p>
 * Concrete implementations must take particular care to ensure the non-null
 * contract detailed for each method is enforced. See
 * {@link org.acegisecurity.userdetails.User} for a
 * reference implementation (which you might like to extend).
 * </p>
 *
 * <p>
 * Concrete implementations should be immutable (value object semantics,
 * like a String). This is because the <code>UserDetails</code> will be
 * stored in caches and as such multiple threads may use the same instance.
 * </p>
 *
 * @author Ben Alex
 * @version $Id: UserDetails.java 1784 2007-02-24 21:00:24 +0000 (Sat, 24 Feb 2007) luke_t $
 */
public interface UserDetails extends Serializable {
    //~ Methods ========================================================================================================

    /**
     * Returns the authorities granted to the user. Cannot return <code>null</code>.
     *
     * @return the authorities (never <code>null</code>)
     */
    GrantedAuthority[] getAuthorities();

    /**
     * Returns the password used to authenticate the user. Cannot return <code>null</code>.
     *
     * @return the password (never <code>null</code>)
     */
    String getPassword();

    /**
     * Returns the username used to authenticate the user. Cannot return <code>null</code>.
     *
     * @return the username (never <code>null</code>)
     */
    String getUsername();

    /**
     * Indicates whether the user's account has expired. An expired account cannot be authenticated.
     *
     * @return <code>true</code> if the user's account is valid (ie non-expired), <code>false</code> if no longer valid
     *         (ie expired)
     */
    boolean isAccountNonExpired();

    /**
     * Indicates whether the user is locked or unlocked. A locked user cannot be authenticated.
     *
     * @return <code>true</code> if the user is not locked, <code>false</code> otherwise
     */
    boolean isAccountNonLocked();

    /**
     * Indicates whether the user's credentials (password) has expired. Expired credentials prevent
     * authentication.
     *
     * @return <code>true</code> if the user's credentials are valid (ie non-expired), <code>false</code> if no longer
     *         valid (ie expired)
     */
    boolean isCredentialsNonExpired();

    /**
     * Indicates whether the user is enabled or disabled. A disabled user cannot be authenticated.
     *
     * @return <code>true</code> if the user is enabled, <code>false</code> otherwise
     */
    boolean isEnabled();
}

看着很长很累是吧  但是一个好的接口的重要性不言而喻,接口更像是一个规范,比如说你实现了其中的isAccountNonLocked接口

那么返回true就表示账号没有被锁定 否则false就代表可以锁定。我在接口上已经明确了定义,那么你的实现就要乖乖遵守。不能不同实现不同语义。而且这个接口很多情况都考虑到了,什么账号过期 凭证失效。因此好的框架肯定适应于大部分的业务不会只应付简单情况,即使出现了特殊情况 比如你会说 这里没有我想要的cid字段(备注 cid做推送的时候用于标注每个手机的设备号),很简单,实现这个接口再加入你的特殊字段即可。说白了就是要有一种面向接口开发的思想,不要一上来就定义一个实体类。

仔细看user类的实现 很有意思 因此面向接口思维开发后 需要写很多代码 但是这些代码具有很强的生命力了 需要好好体会

/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.acegisecurity.userdetails;

import org.acegisecurity.GrantedAuthority;

import org.springframework.util.Assert;


/**
 * Models core user information retieved by an {@link UserDetailsService}.<p>Implemented with value object
 * semantics (immutable after construction, like a <code>String</code>). Developers may use this class directly,
 * subclass it, or write their own {@link UserDetails} implementation from scratch.</p>
 *
 * @author Ben Alex
 * @version $Id: User.java 1784 2007-02-24 21:00:24 +0000 (Sat, 24 Feb 2007) luke_t $
 */
public class User implements UserDetails {
    //~ Instance fields ================================================================================================

    private static final long serialVersionUID = 1L;
    private String password;
    private String username;
    private GrantedAuthority[] authorities;
    private boolean accountNonExpired;
    private boolean accountNonLocked;
    private boolean credentialsNonExpired;
    private boolean enabled;

    //~ Constructors ===================================================================================================

    /**
     * Construct the <code>User</code> with the details required by
     * {@link org.acegisecurity.providers.dao.DaoAuthenticationProvider}.
     *
     * @param username the username presented to the
     *        <code>DaoAuthenticationProvider</code>
     * @param password the password that should be presented to the
     *        <code>DaoAuthenticationProvider</code>
     * @param enabled set to <code>true</code> if the user is enabled
     * @param authorities the authorities that should be granted to the caller
     *        if they presented the correct username and password and the user
     *        is enabled
     *
     * @throws IllegalArgumentException if a <code>null</code> value was passed
     *         either as a parameter or as an element in the
     *         <code>GrantedAuthority[]</code> array
     *
     * @deprecated use new constructor with extended properties (this
     *             constructor will be removed from release 1.0.0)
     */
    public User(String username, String password, boolean enabled, GrantedAuthority[] authorities)
        throws IllegalArgumentException {
        this(username, password, enabled, true, true, authorities);
    }

    /**
     * Construct the <code>User</code> with the details required by
     * {@link org.acegisecurity.providers.dao.DaoAuthenticationProvider}.
     *
     * @param username the username presented to the
     *        <code>DaoAuthenticationProvider</code>
     * @param password the password that should be presented to the
     *        <code>DaoAuthenticationProvider</code>
     * @param enabled set to <code>true</code> if the user is enabled
     * @param accountNonExpired set to <code>true</code> if the account has not
     *        expired
     * @param credentialsNonExpired set to <code>true</code> if the credentials
     *        have not expired
     * @param authorities the authorities that should be granted to the caller
     *        if they presented the correct username and password and the user
     *        is enabled
     *
     * @throws IllegalArgumentException if a <code>null</code> value was passed
     *         either as a parameter or as an element in the
     *         <code>GrantedAuthority[]</code> array
     *
     * @deprecated use new constructor with extended properties (this
     *             constructor will be removed from release 1.0.0)
     */
    public User(String username, String password, boolean enabled, boolean accountNonExpired,
        boolean credentialsNonExpired, GrantedAuthority[] authorities)
        throws IllegalArgumentException {
        this(username, password, enabled, accountNonExpired, credentialsNonExpired, true, authorities);
    }

    /**
     * Construct the <code>User</code> with the details required by
     * {@link org.acegisecurity.providers.dao.DaoAuthenticationProvider}.
     *
     * @param username the username presented to the
     *        <code>DaoAuthenticationProvider</code>
     * @param password the password that should be presented to the
     *        <code>DaoAuthenticationProvider</code>
     * @param enabled set to <code>true</code> if the user is enabled
     * @param accountNonExpired set to <code>true</code> if the account has not
     *        expired
     * @param credentialsNonExpired set to <code>true</code> if the credentials
     *        have not expired
     * @param accountNonLocked set to <code>true</code> if the account is not
     *        locked
     * @param authorities the authorities that should be granted to the caller
     *        if they presented the correct username and password and the user
     *        is enabled
     *
     * @throws IllegalArgumentException if a <code>null</code> value was passed
     *         either as a parameter or as an element in the
     *         <code>GrantedAuthority[]</code> array
     */
    public User(String username, String password, boolean enabled, boolean accountNonExpired,
        boolean credentialsNonExpired, boolean accountNonLocked, GrantedAuthority[] authorities)
        throws IllegalArgumentException {
        if (((username == null) || "".equals(username)) || (password == null)) {
            throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
        }

        this.username = username;
        this.password = password;
        this.enabled = enabled;
        this.accountNonExpired = accountNonExpired;
        this.credentialsNonExpired = credentialsNonExpired;
        this.accountNonLocked = accountNonLocked;
        setAuthorities(authorities);
    }

    //~ Methods ========================================================================================================

    public boolean equals(Object rhs) {
        if (!(rhs instanceof User) || (rhs == null)) {
            return false;
        }

        User user = (User) rhs;

        // We rely on constructor to guarantee any User has non-null and >0
        // authorities
        if (user.getAuthorities().length != this.getAuthorities().length) {
            return false;
        }

        for (int i = 0; i < this.getAuthorities().length; i++) {
            if (!this.getAuthorities()[i].equals(user.getAuthorities()[i])) {
                return false;
            }
        }

        // We rely on constructor to guarantee non-null username and password
        return (this.getPassword().equals(user.getPassword()) && this.getUsername().equals(user.getUsername())
                && (this.isAccountNonExpired() == user.isAccountNonExpired())
                && (this.isAccountNonLocked() == user.isAccountNonLocked())
                && (this.isCredentialsNonExpired() == user.isCredentialsNonExpired())
                && (this.isEnabled() == user.isEnabled()));
    }

    public GrantedAuthority[] getAuthorities() {
        return authorities;
    }

    public String getPassword() {
        return password;
    }

    public String getUsername() {
        return username;
    }

    public int hashCode() {
        int code = 9792;

        if (this.getAuthorities() != null) {
            for (int i = 0; i < this.getAuthorities().length; i++) {
                code = code * (this.getAuthorities()[i].hashCode() % 7);
            }
        }

        if (this.getPassword() != null) {
            code = code * (this.getPassword().hashCode() % 7);
        }

        if (this.getUsername() != null) {
            code = code * (this.getUsername().hashCode() % 7);
        }

        if (this.isAccountNonExpired()) {
            code = code * -2;
        }

        if (this.isAccountNonLocked()) {
            code = code * -3;
        }

        if (this.isCredentialsNonExpired()) {
            code = code * -5;
        }

        if (this.isEnabled()) {
            code = code * -7;
        }

        return code;
    }

    public boolean isAccountNonExpired() {
        return accountNonExpired;
    }

    public boolean isAccountNonLocked() {
        return this.accountNonLocked;
    }

    public boolean isCredentialsNonExpired() {
        return credentialsNonExpired;
    }

    public boolean isEnabled() {
        return enabled;
    }

    protected void setAuthorities(GrantedAuthority[] authorities) {
        Assert.notNull(authorities, "Cannot pass a null GrantedAuthority array");

        for (int i = 0; i < authorities.length; i++) {
            Assert.notNull(authorities[i],
                "Granted authority element " + i + " is null - GrantedAuthority[] cannot contain any null elements");
        }

        this.authorities = authorities;
    }

    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append(super.toString()).append(": ");
        sb.append("Username: ").append(this.username).append("; ");
        sb.append("Password: [PROTECTED]; ");
        sb.append("Enabled: ").append(this.enabled).append("; ");
        sb.append("AccountNonExpired: ").append(this.accountNonExpired).append("; ");
        sb.append("credentialsNonExpired: ").append(this.credentialsNonExpired).append("; ");
        sb.append("AccountNonLocked: ").append(this.accountNonLocked).append("; ");

        if (this.getAuthorities() != null) {
            sb.append("Granted Authorities: ");

            for (int i = 0; i < this.getAuthorities().length; i++) {
                if (i > 0) {
                    sb.append(", ");
                }

                sb.append(this.getAuthorities()[i].toString());
            }
        } else {
            sb.append("Not granted any authorities");
        }

        return sb.toString();
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值