天天看點

JavaWeb 利用springsecurity做使用者權限限制

JavaWeb 利用springsecurity做使用者權限限制。

一、概述

不同的user(使用者)需要不同的role(角色),不同的role(角色)又會需要不同的resource(資源權限),比如說我王二,是個管理者(admin),我的權限大到什麼都能操作,包括建立一個代理(proxy),再比如說我弟弟王三,是個代理(proxy),他卻不能建立代理,他權限不夠大。

利用springsecurity來實作的話,就非常簡便(當然了,必須先做點準備工作)。

<security:authorize name="newAgentPage">
    <li><a class="add" title="建立代理"><span>建立代理</span></a></li>
</security:authorize>           

注釋一下:

  1. security是規定的一個taglib前标記。
  2. authorize是規定的一個tld後标記。
  3. name是規定的适配屬性。
  4. newAgentPage是規定的權限名字。

二、直覺體驗

來看看我王二和弟弟王三的操作權限效果:

JavaWeb 利用springsecurity做使用者權限限制

三、具體實作

1、添加security字首
<%@ taglib prefix="security" uri="http://www.springsecurity.org/jsp"%>           
2、添加authorize字尾
<?xml version="1.0" encoding="UTF-8" ?>  
<taglib xmlns="http://java.sun.com/xml/ns/javaee"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   
    http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"  
    version="2.1">  
    <description>  
    <![CDATA[security Tags]]>  
    </description>  
    <tlib-version>1.0</tlib-version>  
    <short-name>security</short-name>  
    <uri>http://www.springsecurity.org/jsp</uri>  
    <tag>  
        <description>  
        <![CDATA[authorize Tag]]>  
        </description>  
        <name>authorize</name>  
        <tag-class>  
            com.honzh.security.filter.tag.AuthorizeTag
        </tag-class>  
        <body-content>JSP</body-content>  
        <attribute>  
            <name>name</name>  
            <required>false</required>  
            <rtexprvalue>true</rtexprvalue>  
            <type>java.lang.String</type>  
        </attribute>  
    </tag>  
</taglib>             

把以上xml内容儲存到WebContent/WEB-INF目錄下的authorize.tld檔案中。

稍作注釋:

  1. name标簽中authorize就是定義的字尾名。
  2. tag-class标簽中為繼承BodyTagSupport标記的子類,3小節中介紹。
  3. attribute标簽中定義了name屬性,用來頁面上傳遞name的value值。
3、AuthorizeTag類
package com.honzh.security.filter.tag;

import java.util.HashMap;
import java.util.List;

import javax.servlet.jsp.tagext.BodyTagSupport;

import org.apache.log4j.Logger;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

import com.honzh.biz.database.entity.security.SecurityUserDto;

public class AuthorizeTag extends BodyTagSupport {
    private static Logger logger = Logger.getLogger(AuthorizeTag.class);

    private static final long serialVersionUID = -5772328723066649929L;

    // 頁面上設定的name值
    private String name;

    /*
     * (non-Javadoc)
     * 
     * @see javax.servlet.jsp.tagext.BodyTagSupport#doStartTag()
     */
    @SuppressWarnings("unchecked")
    public int doStartTag() {
        try {
            // 登陸使用者的權限對象
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();

            if (auth == null) {
                return SKIP_BODY;
            }

            // 封裝了一系列便捷資訊的登陸使用者
            SecurityUserDto securityUserDto = (SecurityUserDto) auth.getPrincipal();

            // 比對使用者是否具有該權限
            List<HashMap<String, String>> resources = securityUserDto.getResources();
            for (HashMap<String, String> resource : resources) {
                if (resource.get("name").equals(this.getName())) {
                    return EVAL_BODY_INCLUDE;
                }
            }

        } catch (Exception e) {
            logger.error(e.getMessage());
            logger.error(e.getMessage(), e);
        }

        return SKIP_BODY;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
           

稍作介紹:

  1. 對于BodyTagSupport 類,你可以參照自定義jsp标簽: TagSupport與BodyTagSupport的差別 (轉),了解一下類方法介紹,以及常量作用。
  2. SecurityUserDto 類是針對我項目封裝的使用者權限類,主要作用就是擷取登陸使用者的角色,角色對應的權限,限于篇幅,本篇隻做簡單的介紹。
4、SecurityUserDto 類
package com.honzh.biz.database.entity.security;

import java.util.Collection;
import java.util.List;

import org.springframework.security.core.GrantedAuthority;

@SuppressWarnings("rawtypes")
public class SecurityUserDto extends SecurityUser {
    private static final long serialVersionUID = -2841646575237530938L;
    private Integer id;
    private String rolename;
    private List  resources;

    public SecurityUserDto() {
    }

    public SecurityUserDto(String username, String password, Integer id,  boolean enabled,
            Collection<GrantedAuthority> authorities, List resources) {
        super(username, password, enabled, authorities);
        this.id = id;
        this.setResources(resources);
    }
/**
     * @return the rolename
     */
    public String getRolename() {
        return rolename;
    }

    /**
     * @param rolename
     *            the rolename to set
     */
    public void setRolename(String rolename) {
        this.rolename = rolename;
    }
    public Integer getId() {
        return this.id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public List getResources() {
        return resources;
    }

    public void setResources(List resources) {
        this.resources = resources;
    }
}
           
  1. 限于篇幅,我删掉了一些屬性。
  2. 關鍵内容是rolename、resources、

    Collection<GrantedAuthority> authorities

5、使用者登陸
<security:authentication-manager alias="authenticationManager">
        <security:authentication-provider
            user-service-ref="customUserDetailsService">
            <security:password-encoder hash="md5" />
        </security:authentication-provider>
    </security:authentication-manager>           

稍作解釋:

  1. 以上xml内容片段來自于applicationContext-security.xml,使用過springsecurity的朋友對該檔案都不會陌生。
  2. 使用者登陸時,springsecurity機制會将使用者名和密碼傳遞到指定的customUserDetailsService服務對象。

然後我們來看看customUserDetailsService服務對象:

package com.honzh.spring.service.security.impl;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import com.honzh.biz.database.entity.UserRole;
import com.honzh.biz.database.entity.security.SecurityUserDto;
import com.honzh.biz.database.mapper.ResourceMapper;
import com.honzh.biz.database.mapper.SecurityUserSpecMapper;
import com.honzh.biz.database.mapper.UserRoleMapper;
import com.honzh.spring.service.security.CustomUserDetailsService;

@Service("customUserDetailsService")
public class CustomUserDetailsServiceImpl implements CustomUserDetailsService {
    @Autowired
    private SecurityUserSpecMapper securityUserSpecMapper;
    @Autowired
    private UserRoleMapper userRoleMapper;
    @Autowired
    private ResourceMapper resourceMapper;

    @SuppressWarnings("rawtypes")
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        SecurityUserDto user = this.securityUserSpecMapper.selectByUsername(userName);

        UserRole userRole = this.userRoleMapper.selectByUserid(user.getId());
        List resources = this.resourceMapper.selectResources(user.getUsername(), userRole.getRoleId1());

        Set<GrantedAuthority> auths = new HashSet<GrantedAuthority>();
        auths.add(new GrantedAuthorityImpl(user.getRolename().replaceAll("\\*\\d{1,}\\*", "")));

        return new SecurityUserDto(user.getUsername(), user.getPassword(), user.getId(),
                auths, resources);
    }
}           
  1. 關于如何獲得權限resource,以及SecurityUserDto 對象就不多做介紹了。
  2. 通過loadUserByUsername方法,就把role、resource等資訊全部封裝到

    SecurityContextHolder.getContext().getAuthentication()

    權限對象中了。
6、權限配置

關于權限配置的相關内容也不做介紹了,因為資料表不一緻,大家夥用的方法也不一緻,如果以後需要的話,再另做介紹。

這裡就隻看看頁面上如何配置權限,僅供參考。

JavaWeb 利用springsecurity做使用者權限限制

為“建立代理”建立指定的newAgentPage權限,其父菜單為整個代理清單頁面。

7、為角色配置設定權限

代碼實作上也不多做介紹了。

代理角色不具有“建立代理”的權限。

8、為使用者配置設定角色

代碼實作上不多做介紹了。

繼續閱讀