2019-01-21 Spring Boot +Spring Security认证授权

内容源自很多博客,就不一一列出了

关于本文对spring security的介绍,读者没有一点相关基础是看不懂的,spring boot里面的封装一层套一层,很多东西它都会自己主动去调用,读者没有相关了解很难真正掌握,建议多看一些基础介绍再看本文。

本人也是小白,所以可能有些理解是错的,不过代码是运行过的,确认没有问题。

 

应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分

1. SecurityContextPersistenceFilter   (保存认证信息到SecurityContextHolder)  --> SecurityContextHolder (提供对SecurityContext的访问)--> SecurityContext (持有Authentication对象和其他可能需要的信息--当前正在访问系统的用户的详细信息) -->  Authentication(存有当前用户的权限)--Spring Security方式的认证主体。

2. UsernamePasswordAuthenticationFilter (处理用户认证逻辑过滤器)  -->  获取username 和 password ,实例化为一个Token(令牌:UsernamePasswordAuthenticationToken -- Authentication接口的实例 -- 未认证)  -- >  调用getAuthenticationManager,获取AuthenticationManager。

3.AuthenticationManager(身份认证的主要策略设置接口)  -- > 只有一个authentication()方法,不直接自己处理认证请求,管理了多个AuthenticationProvider接口  -- > ProviderManagger(默认实现上述接口的类,authentication()方法中for循环遍历寻找合适的Provider)。

4.    AuthenticationProvider(处理用户认证的接口)  -- >  authentication()方法【认证方法】和support()方法【是否支持某类型token的方法】--> AbstractUserDetailsAuthenticationProvider(实现上述接口的具体实现类,支持UsernamePasswordAuthenticationProvider Token类型)  --> DaoAuthenticationProvider类(上述的子类)-->  调用getUserDetailsService()获取UserDetailsService对象(loadUserByUsername()方法,返回值为UserDetails--构建Authentication对象必须的信息,可以自定义 )-->  调用loadUserByUsername根据userName获取UserDetail对象(有User非常全面的信息)。

5.对比UserDetail后,Authentication填充完整,认证通过。认证信息保存在SecurityContextHolder中。

SecurityContextHolder.getContext().setAuthentication(authentication)

 

【注】对拦截器的理解:https://blog.csdn.net/Fern2018/article/details/87870077

 

一、User类--继承UserDetails

package com.dongnao.james.model.Sys;

import com.dongnao.james.model.Role;
import com.dongnao.james.model.Sys.SysPermission;
import com.dongnao.james.model.Sys.SysRole;
import com.dongnao.james.model.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import javax.persistence.*;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;


@Table(name = "users")
@Entity
//实现UserDetail接口,用户实体为spring security所使用的用户
public class SysUser  extends UserDetails {
    @Id
    @GeneratedValue
    private Long userId;        //用户id
    private String userName;    //用户名
    private String password;    //用户密码
    private boolean enabled;    //账户是否可用


    //通过关联的方式映射用户和角色多对多的关系
    // cascade表示级联操作   CascadeType.REFRESH级联刷新--会重新查询数据库里的最新数据  FetchType.EAGER急加载--加载一个实体时,急加载的属性会立即从数据库中加载
    @ManyToMany(cascade = {CascadeType.REFRESH}, fetch = FetchType.EAGER) //(驼峰映射)
    @JoinTable(name = "usersRoles",
            joinColumns = {@JoinColumn(name = "userId", referencedColumnName = "userId")},
            inverseJoinColumns = {@JoinColumn(name = "roleId", referencedColumnName = "roleId")})
    private List<SysRole> roles;

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long id) {
        this.userId = id;
    }

    public void setUserName(String username) {
        this.userName = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public List<SysRole> getRoles() {
        return roles;
    }

    public void setRoles(List<SysRole> roles) {
        this.roles = roles;
    }

    @Override
    public String getPassword() {
        return this.password;
    }

    @Override
    public String getUsername() {
        return this.userName;
    }

    // 账户未过期
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    //账户未锁定
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    //密码未过期
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    //账户可用
    @Override
    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    @Override
    //重写getAuthorities()方法,将用户的角色作为权限
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> auths = new ArrayList<>();
        List<SysRole> roles = this.getRoles();
        for (SysRole role : roles) {
            auths.add(new SimpleGrantedAuthority(role.getRoleName()));
        }
        return auths;
    }

//    @Override
//    //重写getAuthorities()方法,将uri作为权限
//    public Collection<? extends GrantedAuthority> getAuthorities() {
//        List<GrantedAuthority> auths = new ArrayList<>();
//        List<SysRole> roles = this.getRoles();
//        for (SysRole role : roles) {
//            List<SysPermission> permissions = role.getPermissions();
//            for(SysPermission permission : permissions){
//                auths.add(new SimpleGrantedAuthority(permission.getUri()));
//            }
//        }
//        return auths;
//    }

}

GrantedAuthority接口 --> 对认证主题的应用层面的授权,含当前用户的权限信息  --> 只有一个getAuthority()方法。

SimpleGrantedAuthority是上述接口的实现类

 

二、UserDetailsService类  -- loadUserByUsername方法

package com.dongnao.james.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import com.dongnao.james.model.Sys.SysUser;
import com.dongnao.james.utils.SQLRepository.SysUserRepository;
import org.springframework.stereotype.Service;


//自定义的时候需要实现一下UserDetailsService接口
@Service
public class UserService implements UserDetailsService {
    @Autowired
    SysUserRepository userRepository;

    @Override
    //重写loadUserByUsername方法获得用户,返回给定用户的UserDetails对象
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //通过JPA来根据用户名查询用户信息
        SysUser user = userRepository.findByUserName(username);
        if (user == null) {
            throw new UsernameNotFoundException("用户名不存在");
        }
        System.out.println("用户密码:"+user.getPassword());
        //SysUser已实现UserDetail接口,可直接返回给spring security使用
        return user;
    }
}

三、Role类

package com.dongnao.james.model.Sys;

import com.dongnao.james.model.Role;
import com.dongnao.james.model.Sys.SysPermission;

import javax.persistence.*;
import java.util.List;

@Table(name="roles")
@Entity
public class SysRole {
    @Id
    @GeneratedValue
    private Long roleId;        //角色id
    private String roleName;    //角色名

    @ManyToMany(cascade = {CascadeType.REFRESH},fetch = FetchType.EAGER)
    @JoinTable(name = "rolesPermission",
            joinColumns = {@JoinColumn(name = "roleId",referencedColumnName = "roleId")},
            inverseJoinColumns = {@JoinColumn(name = "perId",referencedColumnName = "perId")})
    private List<SysPermission> permissions;

    public Long getRoleId() {
        return roleId;
    }

    public void setRoleId(Long id) {
        this.roleId = id;
    }

    public String getRoleName() {
        return roleName;
    }

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

    public List<SysPermission> getPermissions() {
        return permissions;
    }

    public void setPermissions(List<SysPermission> permissions) {
        this.permissions = permissions;
    }
}

 

Permission类

package com.dongnao.james.model.Sys;

import javax.persistence.*;
import java.util.List;

@Entity
@Table(name = "permission")
public class SysPermission {
    @Id
    @GeneratedValue
    private Long perId;         //权限id
    private String perName;     //权限名
    private String description; //描述
    private String uri;         //对应的uri

    public Long getPerId() {
        return perId;
    }

    public void setPerId(Long perId) {
        this.perId = perId;
    }

    public String getPerName() {
        return perName;
    }

    public void setPerName(String perName) {
        this.perName = perName;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getUri() {
        return uri;
    }

    public void setUri(String uri) {
        this.uri = uri;
    }
}

四、数据访问层  -- jpa

package com.dongnao.james.utils.SQLRepository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.dongnao.james.model.Sys.SysUser;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;


//数据访问,根据用户名使用JPA查出用户
public interface SysUserRepository extends JpaRepository<SysUser, Long> {
    SysUser findByUserName(String username);

    SysUser findByUserId(Long userId);

    List<SysUser> findAll();

    void delete(Long userId);

    SysUser saveAndFlush(SysUser user);

    @Transactional
    @Modifying
    @Query(value = "update users set user_name= :userName,password= :password,enabled=:enabled where user_id = :userId",nativeQuery = true)
    void update(@Param("userId") Long userId, @Param("userName") String userName, @Param("password") String password, @Param("enabled") boolean enabled);
    
}

五、自定义了一个springSecurity安全框架的配置类 继承WebSecurityConfigurerAdapter

package com.dongnao.james.config;

import com.dongnao.james.interceptor.MyFilterSecurityInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;

import com.dongnao.james.service.UserService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;


@Configuration
@EnableWebSecurity
//如果要自定义扩展springsecurity配置需要继承WebSecurityConfigurerAdapter
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyFilterSecurityInterceptor myFilterSecurityInterceptor;

    //注册customUserService实例
    @Bean
    UserDetailsService customUserService() {
        return new UserService();
    }

    //配置全局认证相关的信息
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //添加我们自定义的userdetailservice 认证
        auth.userDetailsService(customUserService()).passwordEncoder(new PasswordEncoder() {
            @Override
            public String encode(CharSequence rawPassword) {
                return MD5Util.encode((String) rawPassword);
            }

            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                return encodedPassword.equals(MD5Util.encode((String) rawPassword));
            }
        });
    }

    //具体的权限规则配置
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //请求权限配置
        http.authorizeRequests()
                //其余任何路径请求都需要认证(登录后)才能访问
                .anyRequest().authenticated()
                //通过fromLogin方法来定制登录操作,登录页面公开,不需要认证即可访问
                .and()
                .formLogin()
                .loginPage("/login")
                .successForwardUrl("/index")
                .failureUrl("/login?error")
                .permitAll()
                //通过logout方法来定制注销操作,//注销公开,不需要认证即可注销
                .and()
                .logout()
                .logoutSuccessUrl("/loginOut")
                .permitAll();
        //http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class);

    }
}
六、针对框架个性化定制
package com.dongnao.james.config;


import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;


@Configuration
public class SpringMvcConfig extends WebMvcConfigurerAdapter {      //Spring内部的一种配置方式,针对框架个性化定制
    /**
     * 视图跳转控制器
     **/
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //访问 /login转向login.html页面
        registry.addViewController("/login").setViewName("login");
        //访问 /loginOut转向注销loginOut.html页面
        registry.addViewController("/loginOut").setViewName("loginOut");
    }

    /**
     * 添加拦截器
     **/
//    @Override
//    public void addInterceptors(InterceptorRegistry registry) {
//        // addPathPatterns 用于添加拦截规则
//        // excludePathPatterns 用户排除拦截
//        registry.addInterceptor(new AuthenticationInterceptor()).excludePathPatterns("/jamesStatic/*")
//                .addPathPatterns("/**");
//    }
}

 

七、MD5加密

package com.dongnao.james.config;

import java.security.MessageDigest;

public class MD5Util {
    private static final String SALT = "tamboo";

    public static String encode(String password) {
        password = password + SALT;
        MessageDigest md5 = null;
        try {
            //返回实现指定摘要算法的 MessageDigest 对象。MD5-- 所请求算法的名称
            md5 = MessageDigest.getInstance("MD5");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        char[] charArray = password.toCharArray();
        byte[] byteArray = new byte[charArray.length];

        for (int i = 0; i < charArray.length; i++)
            byteArray[i] = (byte) charArray[i];

        byte[] md5Bytes = md5.digest(byteArray);
        StringBuffer hexValue = new StringBuffer();

        for (int i = 0; i < md5Bytes.length; i++) {
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16) {
                hexValue.append("0");
            }
            hexValue.append(Integer.toHexString(val));      //十六进制
        }
        return hexValue.toString();
    }



    public static void main(String[] args) {
        System.out.println(MD5Util.encode("abel"));

    }
}

八、pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.james</groupId>
    <artifactId>consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>consumer</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
         <thymeleaf.version>3.0.8.RELEASE</thymeleaf.version>
        <thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
        <thymeleaf-extras-springsecurity4.version>3.0.2.RELEASE</thymeleaf-extras-springsecurity4.version>

    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity4</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

九、login.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>登录</title>
    <link rel="stylesheet" th:href="@{css/bootstrap.min.css}"/>
    <link rel="stylesheet" th:href="@{css/signin.css}"/>
    <style type="text/css">
        body {
            padding-top: 50px;
        }

        .starter-template {
            padding: 40px 15px;
            text-align: center;
        }
    </style>
</head>
<body>

<div class="container">
    <div class="starter-template">
      <!---<p th:if="${param.logout}" class="bg-warning">已注销</p>
        <p th:if="${param.error}" class="bg-danger">有错误,请重试</p>--->
        <h2>使用账号密码登录</h2>
        <form class="form-signin" role="form" name="form" th:action="@{/login}" action="/login" method="post">
            <div class="form-group">
                <label for="username">账号</label>
                <input id="username" type="text" class="form-control" name="username" value="" placeholder="账号"/>
            </div>
            <div class="form-group">
                <label for="password">密码</label>
                <input id="password" type="password" class="form-control" name="password" placeholder="密码"/>
            </div>
            <input type="submit" id="login" value="Login" class="btn btn-primary"/>
        </form>
    </div>
</div>


</body>
</html>

index.html

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
    <meta charset="UTF-8"/>
    <title sec:authentication="name">index</title>
    <link rel="stylesheet" th:href="@{css/bootstrap.min.css}"/>
    <style type="text/css">
        body {
            padding-top: 50px;
        }

        .starter-template {
            padding: 40px 15px;
            text-align: center;
        }
    </style>
</head>
<body>

<div class="container">
    <div class="starter-template">
        <p>登录名:<span sec:authentication="name"></span></p>
        <div sec:authentication="principal.authorities"></div>
        <!--<p th:if="${param.logout}" class="bg-warning">已注销</p>-->
        <h1 th:text="${msg.title}"></h1>
        <p class="bg-primary" th:text="${msg.content}"></p>
        <div sec:authorize="hasRole('ROLE_ADMIN')">
            <p class="bg-info" th:text="${msg.info}"></p>
        </div>
        <div sec:authorize="hasRole('ROLE_USER')">
            <p class="bg-info">无更多显示信息</p>
        </div>
        <p>Click <a th:href="@{/home}">here</a> go to home page.</p>
        <p>Click <a th:href="@{/admin}">here</a> go to admin page.</p>
        <form th:action="@{/logout}" method="post">
            <input type="submit" class="btn btn-primary" value="注销"/>
        </form>
    </div>
</div>
</body>
</html>

十、application.properties

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123
logging.level.org.springframework.security=info
spring.thymeleaf.cache=false

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
#spring.jackson.serialization.indent_output=true

spring.thymeleaf.prefix=classpath:/jamesHtml/

spring.resources.static-locations=classpath:/jamesStatic/



#spring.thymeleaf.mode=HTML

#数据表命名下划线问题
#spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

十一、添加拦截器

FilterInvocationSecurityMetadataSource
package com.dongnao.james.interceptor;

import com.dongnao.james.model.Sys.SysPermission;
import com.dongnao.james.model.Sys.SysRole;
import com.dongnao.james.utils.SQLRepository.SysPermissionRepository;
import com.dongnao.james.utils.SQLRepository.SysRoleRepository;
import org.springframework.beans.factory.annotation.Autowired;
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.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

@Service
public class MyInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
    @Autowired
    private SysPermissionRepository permissionRepository;
    @Autowired
    private SysRoleRepository roleRepository;

    private HashMap<String, Collection<ConfigAttribute>> map = null;

    /**
     * 加载权限表中所有权限
     */
    public void loadResourceDefine() {
        map = new HashMap<>();
        Collection<ConfigAttribute> array;
        ConfigAttribute cfg;
        List<SysRole> roles = roleRepository.findAll();
        for (SysRole role : roles){
            List<SysPermission> permissions = role.getPermissions();
            array = new ArrayList<>();
            cfg = new SecurityConfig(role.getRoleName());
            array.add(cfg);
            for (SysPermission permission : permissions) {
                //用权限的getUrl() 作为map的key,用ConfigAttribute的集合作为 value,
                map.put(permission.getUri(), array);
            }
        }
    }

    //此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        if (map == null)
            loadResourceDefine();
        //object 中包含用户请求的request 信息
        HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
        //匹配HttpServletRequest的简单策略接口RequestMatcher的实现类AntPathRequestMatcher
        AntPathRequestMatcher matcher;
        String resUri;
        for (Iterator<String> iter = map.keySet().iterator(); iter.hasNext(); ) {
            resUri = iter.next();
            matcher = new AntPathRequestMatcher(resUri);
            if (matcher.matches(request)) {
                return map.get(resUri);
            }
        }
        return null;
    }

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

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

}
AccessDecisionManager
package com.dongnao.james.interceptor;

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;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Service;

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

@Service
public class MyAccessDecisionManager implements AccessDecisionManager {

    // decide 方法是判定是否拥有权限的决策方法,参数object 包含客户端发起的请求的requset信息
    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        if(null == configAttributes || configAttributes.size() <= 0){
            return;
        }
        ConfigAttribute c;
        String needRole;
        for(Iterator<ConfigAttribute> iter = configAttributes.iterator();iter.hasNext();){
            c = iter.next();
            needRole = c.getAttribute();
            System.out.println("acc 需要的角色:"+needRole);
            for(GrantedAuthority ga : authentication.getAuthorities()){
                if(needRole.trim().equals(ga.getAuthority())){
                    return;
                }else if(ga.getAuthority().equals("ROLE_ANONYMOUS")){
                   // 用户没有登陆!
                    return ;
                }
            }
        }

        throw new AccessDeniedException("You don't have right");
    }

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

    @Override
    public boolean supports(ConfigAttribute configAttribute) {
        return true;
    }

}
MyFilterSecurityInterceptor  --> FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter
package com.dongnao.james.interceptor;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDecisionManager;
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;
import org.springframework.stereotype.Service;

import javax.servlet.*;
import java.io.IOException;

@Service
public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
    @Autowired
    private FilterInvocationSecurityMetadataSource securityMetadataSource;

    @Autowired
    public void setAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager) {
        super.setAccessDecisionManager(myAccessDecisionManager);
    }

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

    @Override
    public void destroy() {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        FilterInvocation filterInvocation = new FilterInvocation(servletRequest,servletResponse,filterChain);
        invoke(filterInvocation);
    }

    public void invoke(FilterInvocation filterInvocation) throws IOException,ServletException{
        /**
         * filterInvocation里面有一个被拦截的url
         * 里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限
         * 再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够访问
         */

        InterceptorStatusToken token = super.beforeInvocation(filterInvocation);
        try{
            //执行下一个拦截器
            filterInvocation.getChain().doFilter(filterInvocation.getRequest(),filterInvocation.getResponse());
        }finally {
            super.afterInvocation(token,null);
        }
    }

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

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

    }
}

或者采用如下方法

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值