} } }

    Spring Security3简单应用(权限设备在数据库中)

    添加时间:2013-5-14 点击量:

      1、权限设备在数据库中,典范的五张表。


        1)t_user  用户表


        2)t_role  角色表


        3)t_user_role  用户-角色接洽关系表 


        4)t_resource  资料表


        5)t_role_resource  角色-资料接洽关系表


      2、建表语句



    DROP TABLE IF EXISTS `t_resource`;
    
    CREATE TABLE `t_resource` (
    `id`
    int11NOT NULL AUTO_INCREMENT ,
    `name`
    varchar32CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
    `url`
    varchar200CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
    PRIMARY KEY (`id`)


    DROP TABLE IF EXISTS `t_role`;
    CREATE TABLE `t_role` (
    `id`
    int11NOT NULL AUTO_INCREMENT ,
    `name`
    varchar32CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
    PRIMARY KEY (`id`)


    DROP TABLE IF EXISTS `t_role_resource`;
    CREATE TABLE `t_role_resource` (
    `id`
    int11NOT NULL AUTO_INCREMENT ,
    `role_id`
    int11NULL DEFAULT NULL
    `resource_id`
    int11NULL DEFAULT NULL
    PRIMARY KEY (`id`)


    CREATE TABLE `t_user` (
    `id`
    int11NOT NULL AUTO_INCREMENT ,
    `account`
    varchar20CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
    `password`
    varchar256CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
    PRIMARY KEY (`id`)


    DROP TABLE IF EXISTS `t_user_role`;
    CREATE TABLE `t_user_role` (
    `id`
    int11NOT NULL AUTO_INCREMENT ,
    `
    user_id` int11NULL DEFAULT NULL
    `role_id`
    int11NULL DEFAULT NULL
    PRIMARY KEY (`id`)


      3、对应的范畴实体


        1)用户




    package cn.luxh.app.domain;
    
    /
    用户
    @author Luxh
    /
    public class User {

    private Integer id;
    /帐号/
    private String account;
    /暗码/
    private String password;


    @Override
    public int hashCode() {
    return account.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
    User user
    = (User) obj;
    return this.account.equals(user.getAccount());
    }

    //getter setter
    //... }



        2)角色




    package cn.luxh.app.domain;
    

    /
    角色
    @author Luxh
    /
    public class Role {

    private Integer id;
    /角色名称/
    private String name;

    //getter setter
    //...
    }



        3)用户-角色




    package cn.luxh.app.domain;
    
    /
    用户角色
    @author Luxh
    /
    public class UserRole {
    private Integer id;
    /用户id/
    private Integer userId;
    /角色id/
    private Integer roleId;

    //getter setter
    //...
    }



        4)资料



    package cn.luxh.app.domain;
    

    /
    资料
    @author Luxh
    /
    public class Resource {

    private Integer id;
    /资料名称/
    private String name;
    /接见地址/
    private String url;

    //getter setter
    }


        5)角色-资料



    package cn.luxh.app.domain;
    
    /
    角色资料
    @author Luxh
    /
    public class RoleResource {
    private Integer id;
    /角色id/
    private Integer roleId;
    /资料id/
    private Integer resourceId;

    //getter setter
    }


      4、设备文件


        在web.xml文件中加上如下内容:




    <!-- SpringSecurity权限框架 -->  
    
    <filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>
    org.springframework.web.filter.DelegatingFilterProxy
    </filter-class>
    </filter>
    <filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/</url-pattern>
    </filter-mapping>

    <!-- 获取Spring Security session的生命周期-->
    <listener>
    <listener-class>
    org.springframework.security.web.session.HttpSessionEventPublisher
    </listener-class>
    </listener>



        当然设备spring器的时辰得把springsecurity的权限设备文件给加载进去:




    <!-- 设备Spring器 -->
    
    <listener>
    <listener-class>
    org.springframework.web.context.ContextLoaderListener
    </listener-class>
    </listener>
    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml,classpath:application-security.xml</param-value>
    </context-param>



        权限设备文件内容如下:



    <?xml version=1.0 encoding=UTF-8?>
    
    <beans:beans xmlns=http://www.springframework.org/schema/security
    xmlns:beans
    =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-3.2.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-3.1.xsd
    >


    <http pattern=/login security=none />
    <http pattern=/resources/ security=none />


    <http auto-config=true use-expressions=true access-denied-page=/denied>
    <!-- default-target-url 指定了从登录页面登录掉队行跳转的页面 always-use-default-target true默示登录成功后强迫跳转
    authentication-failure-url 默示验证失败掉队入的页面 login-processing-url 设置验证登录验证地址,若是不设置,默认是j_spring_security_check
    username-parameter,password-parameter 设置登录用户名和暗码的恳求name,默认:j_username,j_password
    default-target-url=/user/home
    -->
    <form-login login-page=/login
    always-use-default-target
    =true
    authentication-failure-url
    =/login?error=1
    authentication-success-handler-ref
    =successHandler />

    <logout logout-success-url=/login />

    <!-- error-if-maximum-exceeded 后登岸的账号会挤掉第一次登岸的账号
    session-fixation-protection
    防止捏造sessionid进击. 用户登录成功后会烧毁用户当前的session.
    创建新的session,并把用户信息复制到新session中.
    -->

    <session-management invalid-session-url=/login?error=3
    session-fixation-protection
    =none>
    <concurrency-control max-sessions=1
    error-if-maximum-exceeded
    =true expired-url=/login?error=2 /><!-- 阻拦第二次登录 -->
    </session-management>
    <custom-filter ref=appInterceptor before=FILTER_SECURITY_INTERCEPTOR/>
    </http>


    <authentication-manager alias=appAuthenticationManager>
    <authentication-provider user-service-ref=userDetailsService>
    </authentication-provider>
    </authentication-manager>

    <beans:bean id=appInterceptor class=cn.luxh.app.security.AppSecurityInterceptor>
    <beans:property name=authenticationManager ref=appAuthenticationManager/>
    <beans:property name=accessDecisionManager ref=appAccessDescisionManager/>
    <beans:property name=securityMetadataSource ref=appSecurityMetadataSource/>
    </beans:bean>



    <beans:bean id=userDetailsService class=cn.luxh.app.security.UserDetailsServiceImpl />

    <beans:bean id=appSecurityMetadataSource class=cn.luxh.app.security.AppSecurityMetadataSource>
    <beans:constructor-arg name=roleService ref=roleService></beans:constructor-arg>
    <beans:constructor-arg name=resourceService ref=resourceService></beans:constructor-arg>
    </beans:bean>

    <beans:bean id=appAccessDescisionManager class=cn.luxh.app.security.AppAccessDescisionManager/>

    <beans:bean id=roleService class=cn.luxh.app.service.RoleServiceImpl/>

    <beans:bean id=resourceService class=cn.luxh.app.service.ResourceServiceImpl/>

    <!-- 登录成功营业处理惩罚 -->
    <beans:bean id=successHandler
    class
    =cn.luxh.app.security.LoginAuthenticationSuccessHandler>
    <beans:property name=url value=/index></beans:property>
    </beans:bean>

    </beans:beans>


      5、权限设备文件中的关键类


        1)UserDetailsServiceImpl



    package cn.luxh.app.security;
    

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

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;

    import cn.luxh.app.domain.Role;
    import cn.luxh.app.domain.User;
    import cn.luxh.app.exception.UserException;
    import cn.luxh.app.persistence.RoleMapper;
    import cn.luxh.app.persistence.UserMapper;

    public class UserDetailsServiceImpl implements UserDetailsService{

    private static Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RoleMapper roleMapper;

    /
    @param account 登录帐号
    /
    public UserDetails loadUserByUsername(String account)
    throws UsernameNotFoundException {
    log.info(
    登录账号:+account);
    org.springframework.security.core.userdetails.User userDetails
    = null;
    try {
    User user
    = userMapper.ByAccount(account);
    if(user == null) {
    throw new UserException(帐号:+account+ 不存在!);
    }
    Collection
    <GrantedAuthority> grantedAuthorities = getGrantedAuthorities(user);

    boolean enables = true;
    boolean accountNonExpired = true;
    boolean credentialsNonExpired = true;
    boolean accountNonLocked = true;
    userDetails
    = new org.springframework.security.core.userdetails.User(user.getAccount(), user.getPassword(), enables, accountNonExpired, credentialsNonExpired, accountNonLocked, grantedAuthorities);
    }
    catch(Exception e) {
    log.error(e.getMessage());
    e.printStackTrace();
    }
    return userDetails;
    }

    /
    按照用户获取该用户拥有的角色
    @param user
    @return
    /
    private Set<GrantedAuthority> getGrantedAuthorities(User user) {
    Set
    <GrantedAuthority> grantedAuthorities = new HashSet<GrantedAuthority>();
    List
    <Role> roles = roleMapper.ByUserId(user.getId());
    if(roles != null) {
    for(Role role : roles) {
    grantedAuthorities.add(
    new SimpleGrantedAuthority(role.getName()));
    }
    }
    return grantedAuthorities;
    }

    }


        2)AppSecurityInterceptor


    View Code

    package cn.luxh.app.security;
    

    import java.io.IOException;

    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.security.access.SecurityMetadataSource;
    import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
    import org.springframework.security.access.intercept.InterceptorStatusToken;
    import org.springframework.security.web.FilterInvocation;
    import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;


    /
    自定义阻碍器
    @author Luxh
    /
    public class AppSecurityInterceptor extends AbstractSecurityInterceptor implements Filter{

    private static Logger log = LoggerFactory.getLogger(AppSecurityInterceptor.class);

    private FilterInvocationSecurityMetadataSource securityMetadataSource;



    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain filterChain)
    throws IOException, ServletException {
    log.info(
    开端阻碍......);
    FilterInvocation fi
    = new FilterInvocation(request, response, filterChain);
    InterceptorStatusToken token
    = super.beforeInvocation(fi);
    try {
    fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
    }
    catch (Exception e) {
    e.printStackTrace();
    }
    finally{
    super.afterInvocation(token,null);
    }
    }

    @Override
    public Class<?> getSecureObjectClass() {
    return FilterInvocation.class;
    }

    @Override
    public SecurityMetadataSource obtainSecurityMetadataSource() {
    return securityMetadataSource;
    }


    @Override
    public void init(FilterConfig arg0) throws ServletException {

    }

    @Override
    public void destroy() {

    }

    public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
    return securityMetadataSource;
    }

    public void setSecurityMetadataSource(
    FilterInvocationSecurityMetadataSource securityMetadataSource) {
    this.securityMetadataSource = securityMetadataSource;
    }




    }



        3)AppAccessDescisionManager


    View Code

    package cn.luxh.app.security;
    

    import java.util.Collection;
    import java.util.Iterator;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.security.access.AccessDecisionManager;
    import org.springframework.security.access.AccessDeniedException;
    import org.springframework.security.access.ConfigAttribute;
    import org.springframework.security.authentication.InsufficientAuthenticationException;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.GrantedAuthority;

    /

    接见决定计划器,决意某个用户具有的角色,是否有足够的权限去接见某个资料 ;做终极的接见把握决意 .
    @author Luxh

    /
    public class AppAccessDescisionManager implements AccessDecisionManager {

    private static Logger log = LoggerFactory.getLogger(AppAccessDescisionManager.class);

    /
    认证用户是否具有权限接见该url地址
    /
    @Override
    public void decide(Authentication authentication, Object obj,
    Collection
    <ConfigAttribute> configAttributes) throws AccessDeniedException,
    InsufficientAuthenticationException {
    log.info(
    AppAccessDescisionManager 验证用户是否具有接见资料的权限);

    if(configAttributes != null) {
    Iterator
    <ConfigAttribute> it = configAttributes.iterator();
    while(it.hasNext()) {
    //接见资料须要的权限
    String needRole = it.next().getAttribute();
    //authentication.getAuthorities() 用户所有的权限
    for(GrantedAuthority ga:authentication.getAuthorities()){
    if(needRole.equals(ga.getAuthority())){
    return;
    }
    }
    }
    }

    //没有权限
    throw new AccessDeniedException(没有权限接见!);
    }

    /
    启动时辰被AbstractSecurityInterceptor调用,决意AccessDecisionManager是否可以履行传递ConfigAttribute。
    /
    @Override
    public boolean supports(ConfigAttribute arg0) {
    return true;
    }

    /
    被安然阻碍器实现调用,包含安然阻碍器将显示的AccessDecisionManager支撑安然对象的类型
    /
    @Override
    public boolean supports(Class<?> arg0) {
    return true;
    }

    }



        4)AppSecurityMetadataSource


    View Code

    package cn.luxh.app.security;
    

    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.security.access.ConfigAttribute;
    import org.springframework.security.access.SecurityConfig;
    import org.springframework.security.web.FilterInvocation;
    import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
    import org.springframework.util.AntPathMatcher;

    import cn.luxh.app.domain.Resource;
    import cn.luxh.app.domain.Role;
    import cn.luxh.app.service.ResourceService;
    import cn.luxh.app.service.RoleService;


    /
    从数据库中查询出资料和权限(角色),并将它们的关系对应起来
    @author Luxh

    /
    public class AppSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    private static Logger log = LoggerFactory.getLogger(AppSecurityMetadataSource.class);

    private RoleService roleService;

    private ResourceService resourceService;

    public RoleService getRoleService() {
    return roleService;
    }


    public void setRoleService(RoleService roleService) {
    this.roleService = roleService;
    }


    public ResourceService getResourceService() {
    return resourceService;
    }


    public void setResourceService(ResourceService resourceService) {
    this.resourceService = resourceService;
    }



    private AntPathMatcher urlMatcher = new AntPathMatcher();


    / 保存资料和权限的对应关系 key-资料url value-权限 /
    private Map<String,Collection<ConfigAttribute>> relationMap = null;


    public AppSecurityMetadataSource(RoleService roleService,ResourceService resourceService) {
    log.info(
    履行 AppSecurityMetadataSource 机关办法);
    this.roleService = roleService;
    this.resourceService = resourceService;
    loadResourceAndRoleRelation();
    }


    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
    return null;
    }

    /
    按照恳求的url,获取接见该url所需的权限(角色)
    /
    @Override
    public Collection<ConfigAttribute> getAttributes(Object obj)
    throws IllegalArgumentException {
    //获取恳求的url地址
    String requestUrl = ((FilterInvocation)obj).getRequestUrl();
    log.info(
    恳求的 requestUrl :+requestUrl);
    Iterator
    <String> it = relationMap.keySet().iterator();
    while(it.hasNext()) {
    String url
    = it.next();
    log.info(
    设备的 url :+url);
    if(requestUrl.indexOf(?)!=-1) {
    requestUrl
    = requestUrl.substring(0, url.indexOf(?));
    }
    log.info(
    hey man :+url);
    if(urlMatcher.match(url, requestUrl)) {
    log.info(
    已匹配 :+url);
    return relationMap.get(url);
    }
    }
    return null;
    }

    @Override
    public boolean supports(Class<?> arg0) {
    return true;
    }



    /
    加载资料和角色的对应关系
    /
    private void loadResourceAndRoleRelation() {
    relationMap
    = new HashMap<String,Collection<ConfigAttribute>>();
    //查出所有角色
    List<Role> roles = roleService.getAll();
    if(roles != null) {
    for(Role role : roles) {
    //查出某个角色可以接见的资料
    List<Resource> resources = resourceService.getByRoleId(role.getId());
    if(resources != null) {
    for(Resource resource : resources) {
    Collection
    <ConfigAttribute> configAttributes = null;
    ConfigAttribute configAttribute
    = new SecurityConfig(role.getName());
    if(relationMap.containsKey(resource.getUrl())){
    configAttributes
    = relationMap.get(resource.getUrl());
    configAttributes.add(configAttribute);
    }
    else{
    configAttributes
    = new ArrayList<ConfigAttribute>() ;
    configAttributes.add(configAttribute);
    relationMap.put(resource.getUrl(), configAttributes);
    }
    }

    }

    }
    }
    }

    }



        5)LoginAuthenticationSuccessHandler


    View Code

    package cn.luxh.app.security;
    

    import java.io.IOException;

    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

    /
    登录验证成功处理惩罚器
    @author Luxh
    /

    public class LoginAuthenticationSuccessHandler implements AuthenticationSuccessHandler{

    private static Logger log = LoggerFactory.getLogger(LoginAuthenticationSuccessHandler.class);

    //登录验证成功后须要跳转的url
    private String url;

    public void onAuthenticationSuccess(HttpServletRequest request,
    HttpServletResponse response, Authentication authentication)
    throws IOException,
    ServletException {
    log.info(
    登录验证成功:+request.getContextPath()+url);
    //response.sendRedirect(request.getContextPath()+url);
    request.getRequestDispatcher(url).forward(request, response);
    }

    public void setUrl(String url) {
    this.url = url;
    }

    }



      6、此中资料表内容如下


                  


      7、源码,含数据库文件和初始化值


            http://files.cnblogs.com/luxh/app4.rar


      8、在页面上的把握权限


        1)引入标签: <%@ taglib prefix=sec uri=http://www.springframework.org/security/tags %>


        2)应用标签:如下,审核操纵时具有ROLE_ADM权限才可以看到。



    <sec:authorize ifAnyGranted=ROLE_ADM>
    
    <li><a href=javascript:auditPage(¥{ctx}/task/auditPage?taskId=¥{task.taskId})>审核</a></li>
    </sec:authorize>





      

    分享到: