Spring Security权限管理小结

目录
  • 1 Spring Security配置用户名和密码
    • 方式一:在application.properties文件中配置
    • 方式二:代码配置
      • 一、查询user用户所具有的角色
      • 二、配置SecurityConfig
  • 2 HttpSecurity的配置
  • 3 登录/注销表单详细配置
  • 4 多个HttpSecurity的配置
  • 5 密码加密
  • 6 方法安全
  • 7 基于数据库的认证
  • 8 角色继承(在securityConfig中加入代码段)
  • 9 动态配置权限

1 Spring Security配置用户名和密码

方式一:在application.properties文件中配置

# 配置security用户名密码
spring.security.user.password=LIFEILIN
spring.security.user.name=LIFEILIN
spring.security.user.roles=admin

方式二:代码配置

@Configuration
public class securityConfig extends WebSecurityConfigurerAdapter {

    //暂且密码不加密
    @Bean
    PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("LIFEILIN").password("LIFEILIN").roles("admin")   //第一个
                .and()
                .withUser("123").password("123").roles("user"); //第二个
    }
}

2 HttpSecurity的配置

        //配置HttpSecurity拦截规则
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()    //开启配置
                .antMatchers("/admin/**").hasRole("admin")
                .antMatchers("/user/**").hasAnyRole("admin","user")
                .anyRequest().authenticated()  //其他请求登录后即可访问
                .and()
                .formLogin()
                .loginProcessingUrl("/doLogin")
                .permitAll()    //跟登录相关接口直接访问
                .and()
                .csrf().disable();
        }

3 登录/注销表单详细配置

    //配置HttpSecurity拦截规则
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()    //开启配置
                .antMatchers("/admin/**").hasRole("admin")
                .antMatchers("/user/**").hasAnyRole("admin", "user")
                .anyRequest().authenticated()  //其他请求登录后即可访问
                .and()
                .formLogin()
                .loginProcessingUrl("/doLogin")
//                .loginPage("login") //登录页面
                //自定义用户名密码
                .usernameParameter("uname")
                .passwordParameter("passwd")
                //登录成功的处理器(前后端分离)
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException { //authentication为登录成功对象
                        //登录成功,返回json
                        resp.setContentType("application/json;charset=utf-8");
                        PrintWriter out = resp.getWriter();
                        Map<String, Object> map = new HashMap<>();
                        map.put("status", 200);
                        map.put("msg", authentication.getPrincipal());   //登录成功对象
                        out.write(new ObjectMapper().writeValueAsString(map));  //将map转为json写出去
                        out.flush();
                        out.close();
                    }
                })
                //登录失败的处理器(前后端分离)
                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException e) throws IOException, ServletException {
                        resp.setContentType("application/json;charset=utf-8");
                        PrintWriter out = resp.getWriter();
                        Map<String, Object> map = new HashMap<>();
                        map.put("status", 401);
                        if (e instanceof LockedException){  //账号锁定
                            map.put("msg","账号被锁定,登录失败");
                        }else if (e instanceof BadCredentialsException){
                            map.put("msg","用户名和密码输入错误,登录失败");
                        }else if (e instanceof DisabledException){
                            map.put("msg","账号被禁用,登录失败");
                        }else if (e instanceof AccountExpiredException){
                            map.put("msg","账户过期,登录失败");
                        }else if (e instanceof CredentialsExpiredException){
                            map.put("msg","密码过期,登录失败");
                        }else {
                            map.put("msg","登录失败");
                        }
                        out.write(new ObjectMapper().writeValueAsString(map));  //将map转为json写出去
                        out.flush();
                        out.close();
                    }
                })
                .permitAll()    //跟登录相关接口直接访问
                .and()
                //注销登录
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessHandler(new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
                        resp.setContentType("application/json;charset=utf-8");
                        PrintWriter out = resp.getWriter();
                        Map<String, Object> map = new HashMap<>();
                        map.put("status", 200);
                        map.put("msg", "注销登录成功");   //注销登录成功
                        out.write(new ObjectMapper().writeValueAsString(map));  //将map转为json写出去
                        out.flush();
                        out.close();
                    }
                })
                .and()
                .csrf().disable();
    }

4 多个HttpSecurity的配置

配置类不需要继承WebSecurityConfigurerAdapter方法,直接注入:configure方法

@Configuration
public class MultiHttpSecurityConfig {
    //暂且密码不加密
    @Bean
    PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    //配置用户名和密码
    @Autowired
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("LIFEILIN").password("LIFEILIN").roles("admin")   //第一个
                .and()
                .withUser("123").password("123").roles("user"); //第二个
    }

    @Configuration
    @Order(1)
    public static class AdminSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/admin/**").authorizeRequests().anyRequest().hasRole("admin"); //admin角色访问
        }
    }

    @Configuration
    public static class OtherSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests().anyRequest().authenticated()
                    .and()
                    .formLogin()
                    .loginProcessingUrl("/doLogin")
                    .permitAll()
                    .and()
                    .csrf().disable();
        }
    }
}

5 密码加密

相同的明文可加密成不同的密文,不用维护原字段。

@Test
void contextLoads() {
    for (int i=0;i<10;i++){
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        System.out.println(encoder.encode("123"));

    }
}

明文【123】加密后:

$2a 10 10 10SS.YDon5lzqkIFdW8DQYzOTJBvQwkdXHWcHlIfF1fa/wPjJtru5aO
$2a 10 10 10vJsPq4GBtHKmmBQaKTriTO90sFurCEDavZANqCoqGu4gAzXxGLbTC
$2a 10 10 10gZ4H3/tBRpz2lPX0XUI1ber2qsNsKuk38j0iSsATeVOrrWFJIEr1G
$2a 10 10 10h7RiyAXP8JzWGsmAXGZy/uO6ASraQPNryVPl.11vMyUjhSCxS.Sde
$2a 10 10 10BCm3vuueGWdvjG3ciCUZB.6V9y6jMELHqB9iv2DwRJyOkR5jd…4S
$2a 10 10 10rO2894WmxRMtjHVzoYivyuzvje8BrAUjm8YLj3K.i4sQDvpWBtuuy
$2a 10 10 10jTosyN75hwKB3OSQCYY9YOIj6TYZG1FdJXfYCalTUuXpPiI5tv/P.
$2a 10 10 10p95j18H3yRABEScCE/2MqOqYt1ZqArdYhC87BVGEmQvn6znSqKw5G
$2a 10 10 10/y8FGBlvod1Dnq29c2scs.eGnYfvezZIZwfDHoXFfgIVA7H0T17pO
$2a 10 10 10k8IKAv4dBXhooEU8Qgo6E.PcrQ/ICymqNGLyE8Jfo4V1nk61GMeuy

6 方法安全

在配置类中添加注解:@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)

接口都能访问,但进了接口不一定能访问到接口里面的方法!!
【Controller层:】

@Autowired
MethodService methodService;

@GetMapping("/hello1")
public String hello1(){
    return methodService.admin();
}
@GetMapping("/hello2")
public String hello2(){
    return methodService.user();
}
@GetMapping("/hello3")
public String hello3(){
    return methodService.hello();
}

【Service层:】

@Service
public class MethodService {
    @PreAuthorize("hasRole('admin')")
    public String admin() {  //需要admin角色才能访问
        return "hello admin";
    }

    @Secured("ROLE_user")
    public String user(){   //需要user角色才能访问
        return "hello user";
    }

    @PreAuthorize("hasAnyRole('admin','user')") //admin,user两种权限
    public String hello(){
        return "hello hello";
    }
}

7 基于数据库的认证

1、数据库中创建三张表user、role、user_role

2、设置配置文件

# 应用名称
spring.application.name=SpringBoot_11_security
# 应用服务 WEB 访问端口
server.port=8080
#下面这些内容是为了让MyBatis映射
# 指定Mybatis的Mapper文件
mybatis.mapper-locations=classpath:mappers/*xml
# 指定Mybatis的实体目录
mybatis.type-aliases-package=com.example.mybatis.entity
# 数据库驱动:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据源名称
spring.datasource.name=defaultDataSource
# 数据库连接地址
spring.datasource.url=jdbc:mysql://localhost:3306/【数据库名称】?serverTimezone=UTC
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# 数据库用户名&密码:
spring.datasource.username=root
spring.datasource.password=【数据库密码】

3、创建实体User、Role

package com.example.bean;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

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

/**
 * @author 李飞林
 * @ClassName User
 * @mail 1961785612@qq.com
 * @Description TODO
 * @date 2022/8/4 21:46
 */
public class User implements UserDetails {
    private Integer id;
    private String username;
    private String password;
    private Boolean enabled;
    private Boolean locked;
    private List<Role> roles;

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

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

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

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

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

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

    public void setLocked(Boolean locked) {
        this.locked = locked;
    }

    public Integer getId() {
        return id;
    }

    @Override
    public String getUsername() {
        return username;
    }

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

    @Override
    public boolean isAccountNonLocked() {   //账号是否未锁定
        return !locked;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {    //是否可用
        return enabled;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<SimpleGrantedAuthority> authorities=new ArrayList<>();
        for (Role role:roles){
            authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getName()));//角色认证以ROLE_开始
        }
        return authorities;    //返回用户所有角色
    }

    @Override
    public String getPassword() {
        return password;
    }
}
package com.example.bean;

/**
 * @author 李飞林
 * @ClassName Role
 * @mail 1961785612@qq.com
 * @Description TODO
 * @date 2022/8/4 21:49
 */
public class Role {
    private Integer id;
    private String name;
    private String nameZh;

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getNameZh() {
        return nameZh;
    }

    public void setNameZh(String nameZh) {
        this.nameZh = nameZh;
    }
}

4、编写mapper层
UserMapper接口:

package com.example.mapper;

import com.example.bean.Role;
import com.example.bean.User;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

/**
 * @author 李飞林
 * @ClassName UserMapper
 * @mail 1961785612@qq.com
 * @Description TODO
 * @date 2022/8/4 22:01
 */
@Mapper
public interface UserMapper {
    User loadUserByUsername(String username);

    List<Role> getUserRolesById(Integer id);
}

UserMapper.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.mapper.UserMapper">
    <select id="loadUserByUsername" resultType="com.example.bean.User">
        select *
        from user
        where username = #{username};
    </select>
    <select id="getUserRolesById" resultType="com.example.bean.Role">
        select *
        from role
        where id in (select rid from user_role where uid = #{id})
    </select>
</mapper>

5、编写service层:

package com.example.service;

import com.example.bean.User;
import com.example.mapper.UserMapper;
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 org.springframework.stereotype.Service;

/**
 * @author 李飞林
 * @ClassName UserService
 * @mail 1961785612@qq.com
 * @Description TODO
 * @date 2022/8/4 22:01
 */
@Service
public class UserService implements UserDetailsService {
    @Autowired
    UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userMapper.loadUserByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        user.setRoles(userMapper.getUserRolesById(user.getId()));
        return user;
    }
}

6、security安全配置:

package com.example.config;

import com.example.service.UserService;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author 李飞林
 * @ClassName SecurityConfig
 * @mail 1961785612@qq.com
 * @Description TODO
 * @date 2022/8/4 22:35
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    UserService userService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService);
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/dba/**").hasRole("dba")
                .antMatchers("/admin/**").hasRole("admin")
                .antMatchers("/user/**").hasRole("user")
                .anyRequest().authenticated()//其他可访问
                .and()
                .formLogin()
                .permitAll()
                .and()
                .csrf().disable();
    }
}

7、controller层接口调试:

package com.example.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author 李飞林
 * @ClassName HelloController
 * @mail 1961785612@qq.com
 * @Description TODO
 * @date 2022/8/4 22:40
 */
@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "hello security";
    }

    @GetMapping("/dba/hello")
    public String dba() {
        return "hello dba";
    }

    @GetMapping("/admin/hello")
    public String admin() {
        return "hello admin";
    }

    @GetMapping("/user/hello")
    public String user() {
        return "hello user";
    }
}

8 角色继承(在securityConfig中加入代码段)

//角色继承
@Bean
RoleHierarchy roleHierarchy() {
    RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
    String hierarchy = "ROLE_dba > ROLE_admin > ROLE_user"; //dba > admin > user
    roleHierarchy.setHierarchy(hierarchy);
    return roleHierarchy;
}

9 动态配置权限

数据库中的表结构如下:

其中菜单表中已经配置好对应的路径,后面需要从数据库中加载:

一、查询user用户所具有的角色

1、编写实体类User、Role、Menu:
User实现UserDetails接口,实现如下方法:

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    List<SimpleGrantedAuthority> authorities=new ArrayList<>();
    for (Role role :
            roles) {
        authorities.add(new SimpleGrantedAuthority(role.getName()));
    }
    return authorities;
}

2、编写UserService:继承UserDetailsService接口,实现loadUserByUsername方法

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService, UserDetailsService {
    @Autowired
    UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userMapper.loadUserByUsername(username);	//根据登录字符串获获取用户名
        if (user == null) {
            throw new UsernameNotFoundException("用户不存在");
        } else {
            user.setRoles(userMapper.getRolesById(user.getId()));	//根据用户名的ID查询所具有的角色
        }
        return user;
    }
}

3、编写UserMapper接口:

@Mapper
public interface UserMapper extends BaseMapper<User> {

    User loadUserByUsername(String username);

    List<Role> getRolesById(Integer id);
}

4、编写UserMapper.xml:

<select id="loadUserByUsername" resultType="com.lifeilin.pojo.User">
    select *
    from user
    where username = #{username}
</select>

<select id="getRolesById" resultType="com.lifeilin.pojo.Role">
    select *
    from role
    where id in (select rid from user_role where uid = #{id});
</select>

至此,已经从数据库中获取到登录用户user所具备的角色

二、配置SecurityConfig

1、在SecurityConfig类中配置登录权限

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    UserServiceImpl userService;

    @Bean
    PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

	//配置登录
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService);
    }
}

2、配置角色(从数据库中动态加载) 1 在config包中创建MyFilter.java过滤器

在config包中创建MyFilter.java过滤器,实现FilterInvocationSecurityMetadataSource接口,其主要作用是分析请求地址,请求地址必然是menu表中给出的标准地址(如果不是则进行其他操作),根据请求地址分析出需要哪些角色

注意:这里需要提前从数据库查询出所有菜单以及对应的角色。

补充:查询菜单及对应角色(使用Spring Cache作缓存)

1、导入缓存相关依赖

<!--        redis依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--        cache依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

2、需要简单配置一下Redis,Redis的基本信息,另外,这里要用到Cache,因此还需要稍微配置一下Cache,如下:

## 配置redis
#基本属性
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.database=0
spring.redis.password=
#配置cache名称
spring.cache.cache-names=c1

另外,还需要在配置类上添加如下代码,表示开启缓存:

3、Service层缓存的使用
(1)在MenuServiceImpl类上使用@CacheConfig(cacheNames = “c1”)
这个注解在类上使用,用来描述该类中所有方法使用的缓存名称,当然也可以不使用该注解,直接在具体的缓存注解上配置名称。
(2)在MenuServiceImpl类下getAllMenus()方法使用@Cacheable
这个注解一般加在查询方法上,表示将一个方法的返回值缓存起来,默认情况下,缓存的key就是方法的参数,缓存的value就是方法的返回值。

@Service
@CacheConfig(cacheNames = "c1")
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {
    @Autowired
    MenuMapper menuMapper;

    //可以加缓存
    @Cacheable
    public List<Menu> getAllMenus() {
        return menuMapper.getAllMenus();
    }
}
@Mapper
public interface MenuMapper extends BaseMapper<Menu> {

    List<Menu> getAllMenus();
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lifeilin.mapper.MenuMapper">
    <!--    查询所有menu-->
    <!-- resultMap:填入配置的resultMap标签的id值 -->
    <select id="getAllMenus" resultMap="BaseResultMap">
        SELECT m.id,
               m.pattern,
               r.id     AS rid,
               r.NAME   AS rname,
               r.nameZh AS rnameZh
        FROM menu AS m
                 LEFT JOIN menu_role AS mr ON m.id = mr.mid
                 LEFT JOIN role AS r ON mr.rid = r.id
    </select>
    <!-- resultMap最终还是要将结果映射到pojo上,type就是指定映射到哪一个pojo -->
    <resultMap id="BaseResultMap" type="com.lifeilin.pojo.Menu">
        <!-- 定义主键 ,非常重要。如果是多个字段,则定义多个id -->
        <!-- property:主键在pojo中的属性名 -->
        <!-- column:主键在数据库中的列名 -->
        <id property="id" column="id"></id>
        <!-- 定义普通属性 -->
        <result property="pattern" column="pattern"></result>
        <!--collection中property的roles 对应的是Role实体中的属性-->
        <collection property="roles" ofType="com.lifeilin.pojo.Role">
            <id column="rid" property="id"/>
            <result column="rname" property="name"/>
            <result column="rnameZh" property="nameZh"/>
        </collection>
    </resultMap>
</mapper>
@Component
public class MyFilter implements FilterInvocationSecurityMetadataSource {
    //路径匹配符
    AntPathMatcher pathMatcher = new AntPathMatcher();

    @Autowired
    MenuServiceImpl menuService;

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        String requestUrl = ((FilterInvocation) object).getRequestUrl();//获取请求的地址
        List<Menu> allMenus = menuService.getAllMenus();//查询所有菜单
        for (Menu menu : allMenus) {
            if (pathMatcher.match(menu.getPattern(), requestUrl)) { //请求地址与菜单地址匹配上
                List<Role> roles = menu.getRoles(); //获取匹配成功的地址的角色
                String[] rolesStr = new String[roles.size()];
                for (int i = 0; i < roles.size(); i++) {
                    rolesStr[i] = roles.get(i).getName();
                }
                return SecurityConfig.createList(rolesStr);
            }
        }
        return SecurityConfig.createList("ROLE_login"); //没有匹配上,标记符,额外处理
    }

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

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

2、在config包中创建MyAccessDecisionManager类

在config包中创建MyAccessDecisionManager类,目的是通过上一步获取了请求路径需要哪些角色看看数据库中是否具有该角色。

@Component
public class MyAccessDecisionManager implements AccessDecisionManager {
    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { //authentication知道有哪些角色,configAttributes知道需要哪些角色
        //1、遍历需要的角色
        for (ConfigAttribute attribute : configAttributes) {
            if ("ROLE_login".equals(attribute.getAttribute())){//请求地址都没匹配上,说明是登陆后就可访问的请求地址
                if (authentication instanceof AnonymousAuthenticationToken){    //匿名用户(没登陆)
                    throw new AccessDeniedException("非法请求");
                }else {
                    return;
                }
            }
            //2、获取所具备的角色
            Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
            for (GrantedAuthority authority : authorities) {
                if (authority.getAuthority().equals(attribute.getAttribute())){//如果具备所需要的角色
                    return;
                }
            }
        }
        throw new AccessDeniedException("非法请求");
    }

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

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

3、在SecurityConfig引入myAccessDecisionManager + myFilter

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                @Override
                public <O extends FilterSecurityInterceptor> O postProcess(O object) {
                    object.setAccessDecisionManager(myAccessDecisionManager);//
                    object.setSecurityMetadataSource(myFilter);//
                    return object;
                }
            })
            .and()
            .formLogin()
            .permitAll()
            .and()
            .csrf().disable();
}

到此这篇关于Spring Security权限管理的文章就介绍到这了,更多相关Spring Security权限管理内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring Security权限管理实现接口动态权限控制

    SpringBoot实战电商项目mall(30k+star)地址:https://github.com/macrozheng/mall 摘要 权限控管理作为后台管理系统中必要的功能,mall项目中结合Spring Security实现了基于路径的动态权限控制,可以对后台接口访问进行细粒度的控制,今天我们来讲下它的后端实现原理. 前置知识 学习本文需要一些Spring Security的知识,对Spring Security不太了解的朋友可以看下以下文章. mall整合SpringSecurity

  • 话说Spring Security权限管理(源码详解)

    最近项目需要用到Spring Security的权限控制,故花了点时间简单的去看了一下其权限控制相关的源码(版本为4.2). AccessDecisionManager spring security是通过AccessDecisionManager进行授权管理的,先来张官方图镇楼. AccessDecisionManager AccessDecisionManager 接口定义了如下方法: //调用AccessDecisionVoter进行投票(关键方法) void decide(Authent

  • springboot集成springsecurity 使用OAUTH2做权限管理的教程

    Spring Security OAuth2 主要配置,注意application.yml最后的配置resource filter顺序配置,不然会能获取token但是访问一直 没有权限 WebSecurityConfigurerAdapter 所在服务器的web配置 AuthorizationServerConfigurerAdapter 认证服务器配置 ResourceServerConfigurerAdapter 资源服务器配置 这两个配置在 OAuth2Config.java 权限有几种模

  • Spring boot security权限管理集成cas单点登录功能的实现

    目录 1.Springboot集成Springsecurity 2.部署CASserver 3.配置CASclient 挣扎了两周,Spring security的cas终于搞出来了,废话不多说,开篇! 1.Spring boot集成Spring security 本篇是使用spring security集成cas,因此,先得集成spring security新建一个Spring boot项目,加入maven依赖,我这里是用的架构是Spring boot2.0.4+Spring mvc+Spri

  • Spring security实现权限管理示例

    Spring security实现权限管理示例,具体如下: 1.配置文件 1.POM.xml <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.o

  • Spring Security权限管理小结

    目录 1 Spring Security配置用户名和密码 方式一:在application.properties文件中配置 方式二:代码配置 一.查询user用户所具有的角色 二.配置SecurityConfig 2 HttpSecurity的配置 3 登录/注销表单详细配置 4 多个HttpSecurity的配置 5 密码加密 6 方法安全 7 基于数据库的认证 8 角色继承(在securityConfig中加入代码段) 9 动态配置权限 1 Spring Security配置用户名和密码 方

  • java中自定义Spring Security权限控制管理示例(实战篇)

    背景描述 项目中需要做细粒的权限控制,细微至url + httpmethod (满足restful,例如: https://.../xxx/users/1, 某些角色只能查看(HTTP GET), 而无权进行增改删(POST, PUT, DELETE)). 表设计 为避嫌,只列出要用到的关键字段,其余敬请自行脑补. 1.admin_user 管理员用户表, 关键字段( id, role_id ). 2.t_role 角色表, 关键字段( id, privilege_id ). 3.t_privi

  • Spring Security权限想要细化到按钮实现示例

    目录 引言 1. 权限颗粒度 2. 权限表 3. 后端权限判断 4. 角色与权限 4.1 RBAC 简介 4.2 RBAC 的提出 4.3 RBAC 三原则 4.4 RBAC 模型分类 4.4.1 RBAC0 4.4.2 RBAC1 4.4.4 RBAC3 4.5 扩展 5. 表设计 6. 代码实现 引言 因为写了不少 Spring Security 文章的缘故,所以总是有小伙伴来问松哥:按钮级别的权限怎么实现?甚至有一些看过 vhr 的小伙伴也问这种问题,其实有的时候搞得我确实挺郁闷的,最近刚

  • Spring security权限配置与使用大全

    简介 Spring Security 是为了基于Spring的应用程序提供的声明式安全保护的安全性框架.Spring Security 提供了完整的安全性解决方案,它能够在Web请求级别和方法调用级别处理身份认证和授权.因为基于Spring框架,所以SPring Security充分使用了一览注入和面向切面技术. Spring Security 本质上是借助一系列的 Servlet Filter来提供各种安全性功能,但这并不需要我们手动去添加或者创建多个Filter.实际上,我们仅需要配置一个F

  • Spring Security源码解析之权限访问控制是如何做到的

    〇.前文回顾 在实战篇<话说Spring Security权限管理(源码详解)>我们学习了Spring Security强大的访问控制能力,只需要进行寥寥几行的配置就能做到权限的控制,本篇来看看它到底是如何做到的. 一.再聊过滤器链 源码篇中反复提到,请求进来需要经过的是一堆过滤器形成的过滤器链,走完过滤器链未抛出异常则可以继续访问后台接口资源,而最后一个过滤器就是来判断请求是否有权限继续访问后台资源,如果没有则会将拒绝访问的异常往上向异常过滤器抛,异常过滤器会对异常进行翻译,然后响应给客户端

  • spring security 5.x实现兼容多种密码的加密方式

    前言 本文主要给大家介绍了关于spring security 5.x实现兼容多种密码的加密方式,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 1.spring security PasswordEncoder spring security 5不需要配置密码的加密方式,而是用户密码加前缀的方式表明加密方式,如: {MD5}88e2d8cd1e92fd5544c8621508cd706b代表使用的是MD5加密方式: {bcrypt}$2a$10$eZeGvVV2ZXr/vgiV

  • 详解Spring Security 中的四种权限控制方式

    Spring Security 中对于权限控制默认已经提供了很多了,但是,一个优秀的框架必须具备良好的扩展性,恰好,Spring Security 的扩展性就非常棒,我们既可以使用 Spring Security 提供的方式做授权,也可以自定义授权逻辑.一句话,你想怎么玩都可以! 今天松哥来和大家介绍一下 Spring Security 中四种常见的权限控制方式. 表达式控制 URL 路径权限 表达式控制方法权限 使用过滤注解 动态权限 四种方式,我们分别来看.  1.表达式控制 URL 路径权

随机推荐