利用springsecurity做用户权限限制

标签: 利用 springsecurity 用户 | 发表时间:2015-12-05 19:31 | 作者:qing_gee
出处:http://blog.csdn.net

一、概述

不同的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是规定的权限名字。

二、直观体验

来看看我王二和弟弟王三的操作权限效果:
这里写图片描述

三、具体实现

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、权限配置

关于权限配置的相关内容也不做介绍了,因为数据表不一致,大家伙用的方法也不一致,如果以后需要的话,再另做介绍。

这里就只看看页面上如何配置权限,仅供参考。
这里写图片描述

为“新建代理”创建指定的 newAgentPage权限,其父菜单为整个代理列表页面。

7、为角色分配权限

代码实现上也不多做介绍了。

代理角色不具有“新建代理”的权限。
这里写图片描述

8、为用户分配角色

代码实现上不多做介绍了。

为我弟弟王三分配了代理(proxy)的角色。
这里写图片描述


到此就算是全部结束了,后续如果有朋友需要权限分配的介绍,再做说明。

该不该搁下重重的壳,寻找哪里到底有蓝天──周杰伦《蜗牛》
本文出自:【 沉默王二的博客

作者:qing_gee 发表于2015/12/5 11:31:54 原文链接
阅读:59 评论:0 查看评论

相关 [利用 springsecurity 用户] 推荐:

利用springsecurity做用户权限限制

- - CSDN博客推荐文章
不同的user(用户)需要不同的role(角色),不同的role(角色)又会需要不同的resource(资源权限),比如说我王二,是个管理员(admin),我的权限大到什么都能操作,包括新建一个代理(proxy),再比如说我弟弟王三,是个代理(proxy),他却不能新建代理,他权限不够大. 利用springsecurity来实现的话,就非常简便(当然了,必须先做点准备工作).

SpringSecurity个性化配置

- - CSDN博客架构设计推荐文章
现有的数据库中包含以下几张表格用于权限管理. 要求在此基础上集成SpringSecurity,将表格的数据作为数据源来完成登录和权限校验逻辑. SpringSecurity的配置可通过两种方式呈现,基于自身的namespace配置和传统的基于Bean的配置. 通过namespace来配置Security非常简洁,隐藏了很多繁琐的实现细节,但也不便于初学者进行理解,而如果要想对Security进行个性化定制(替换现有功能实现),最好还是采用传统的基于Bean的方式进行配置,虽然结构复杂,但是细节清晰明了.

如何利用新闻APP培养用户粘度

- - 钛媒体网
近一百多年来,总有一些公司很幸运地、有意识或者无意识地站在技术革命的浪尖之上. 一旦处在了那个位置,即使不做任何事,也可以随着波浪顺顺当当地向前漂个十年甚至更长的时间. 在这十几年间,它们代表着科技的浪潮,直到下一波浪潮的来临. (引自吴军的《浪潮之巅》). 图为艾瑞网发布的报告中显示的PC和移动互联网趋势.

利用AI构建动态用户画像的七步法

- - 人人都是产品经理
本篇文章分步为大家详细地介绍了用AI构建动态用户画像的方法,供大家参考学习~. 背景:虽然听过很多用户画像的神奇功能和成功案例,但对用户画像的构建实际是需要从技术和业务高度融合的角度来设计,否则建立的用户画像流于表面的形式而不能发挥作用. 构建用户画像之前,需要先明确用户画像构建的战略意义,设定用户画像使用的基本目标.

IE 9 也沦陷,Google 照样愚弄了 W3C 的技术规范利用 cookie 追踪用户

- - 谷奥——探寻谷歌的奥秘
Google的“cookies门”事件还没完, 就在微软隔岸观火幸灾乐祸一石二鸟之时, 突然发现自己的IE 9其实也中枪了,Google照样找到了自己的办法绕过IE 9的cookies设置,防止自己的追踪型cookies. IE 9的规范要求放置追踪型cookies的网站必须利用 W3C的P3P技术描述出自己将如何利用cookies追踪信息,如果不使用P3P标准,是不允许利用cookies来追踪用户信息的.

三个成功案例告诉你:如何利用博客来建立产品的潜在用户群

- - 谈资网
大部分创业公司选择产品先行,再进行用户累积的策略,当然也有不少公司在推出产品前就已经成功积累了不少目标受众,其中包括 37signals、 SEOmoz和 Mint.com. 他们的做法是做一个分享专业内容和独立价值的博客,借此吸引到目标受众. 37signals于 1999 年以网页设计起家.

用户及用户特征

- Nick - 所有文章 - UCD大社区
要创建1个可以与用户有效交流的网站,必须考虑到与你交流的用户. 理解用户的需求对我们决定网站内容、信息量、用户以及内容结构至关重要. 用户不是被动的接受网站提供的信息,所有人都会不断的地根据自身经验和猜测来理解. 自己在屏幕上看到的内容,即使我们认同是相同语言,但是每个人的理解含义不会完全相同. 我们都会根据自己的知识和经验来理解所看到的内容,(如果你不住再伦敦,就不知道Oyster卡,Oyster卡是乘坐公交交通时用的旅游储值卡).

用户体验

- tal-rasha - 博客园-首页原创精华区
    用户体验是一个很大的话题,先从一个故事说起.     周末参加了两天的PMP培训,听课期间注意到老师的一个细节,在讲选择题的时候,选项A、C读音正常,而“B”老师读为Boy,“D”老师读为Dog.     刚听到的时候大家莞尔一笑,以为这是个善意的玩笑.     很快,我想明白了,B和D的发音类似,容易混淆;Boy和Dog是简单的单词,发音能够明确区分,也没有类似Bog和Doy的读音混淆.

用户研究

- - 技术改变世界 创新驱动中国 - 《程序员》官网
介绍自己的设计流程时,设计师通常都说它是“以人为中心”或是“以用户为中心”的. 笼统地讲,这表示设计师经常要考虑所设计产品的潜在用户,尽力为这些人创造出最好的产品. 这个问题看似简单,实际上却不好回答. 好的设计通常都是从用户研究着手的. 我们如何才能发现人们想要实现的目标. 虽然这样做有时会得到一些有用的信息,但一定要小心地评估人们给出的答案.

利用sockstunnel翻越

- - 0.618網絡空間
首先在你的linux vps上搭建python環境(一般來說,linux vps都已搭好了python 環境). 然後運行如下命令(假設你在/root下):. 這樣在/root/下,就生成了privkey.pem和cacert.pem. 修改sslserver.py裏的. keyfile="privkey.pem",為.