Spring Security权限管理实例分析(security,spring,开发技术)

时间:2024-05-06 01:17:51 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

接下来,请跟着小编一起来学习吧!

    1 Spring Security配置用户名和密码

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

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

    方式二:代码配置

    @Configuration
    publicclasssecurityConfigextendsWebSecurityConfigurerAdapter{

    //暂且密码不加密
    @Bean
    PasswordEncoderpasswordEncoder(){
    returnNoOpPasswordEncoder.getInstance();
    }

    @Override
    protectedvoidconfigure(AuthenticationManagerBuilderauth)throwsException{
    auth.inMemoryAuthentication()
    .withUser("LIFEILIN").password("LIFEILIN").roles("admin")//第一个
    .and()
    .withUser("123").password("123").roles("user");//第二个
    }
    }

    2 HttpSecurity的配置

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

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

    //配置HttpSecurity拦截规则
    @Override
    protectedvoidconfigure(HttpSecurityhttp)throwsException{
    http.authorizeRequests()//开启配置
    .antMatchers("/admin/").hasRole("admin")
    .antMatchers("/user/
    ").hasAnyRole("admin","user")
    .anyRequest().authenticated()//其他请求登录后即可访问
    .and()
    .formLogin()
    .loginProcessingUrl("/doLogin")
    //.loginPage("login")//登录页面
    //自定义用户名密码
    .usernameParameter("uname")
    .passwordParameter("passwd")
    //登录成功的处理器(前后端分离)
    .successHandler(newAuthenticationSuccessHandler(){
    @Override
    publicvoidonAuthenticationSuccess(HttpServletRequestreq,HttpServletResponseresp,Authenticationauthentication)throwsIOException,ServletException{//authentication为登录成功对象
    //登录成功,返回json
    resp.setContentType("application/json;charset=utf-8");
    PrintWriterout=resp.getWriter();
    Map<String,Object>map=newHashMap<>();
    map.put("status",200);
    map.put("msg",authentication.getPrincipal());//登录成功对象
    out.write(newObjectMapper().writeValueAsString(map));//将map转为json写出去
    out.flush();
    out.close();
    }
    })
    //登录失败的处理器(前后端分离)
    .failureHandler(newAuthenticationFailureHandler(){
    @Override
    publicvoidonAuthenticationFailure(HttpServletRequestreq,HttpServletResponseresp,AuthenticationExceptione)throwsIOException,ServletException{
    resp.setContentType("application/json;charset=utf-8");
    PrintWriterout=resp.getWriter();
    Map<String,Object>map=newHashMap<>();
    map.put("status",401);
    if(einstanceofLockedException){//账号锁定
    map.put("msg","账号被锁定,登录失败");
    }elseif(einstanceofBadCredentialsException){
    map.put("msg","用户名和密码输入错误,登录失败");
    }elseif(einstanceofDisabledException){
    map.put("msg","账号被禁用,登录失败");
    }elseif(einstanceofAccountExpiredException){
    map.put("msg","账户过期,登录失败");
    }elseif(einstanceofCredentialsExpiredException){
    map.put("msg","密码过期,登录失败");
    }else{
    map.put("msg","登录失败");
    }
    out.write(newObjectMapper().writeValueAsString(map));//将map转为json写出去
    out.flush();
    out.close();
    }
    })
    .permitAll()//跟登录相关接口直接访问
    .and()
    //注销登录
    .logout()
    .logoutUrl("/logout")
    .logoutSuccessHandler(newLogoutSuccessHandler(){
    @Override
    publicvoidonLogoutSuccess(HttpServletRequestreq,HttpServletResponseresp,Authenticationauthentication)throwsIOException,ServletException{
    resp.setContentType("application/json;charset=utf-8");
    PrintWriterout=resp.getWriter();
    Map<String,Object>map=newHashMap<>();
    map.put("status",200);
    map.put("msg","注销登录成功");//注销登录成功
    out.write(newObjectMapper().writeValueAsString(map));//将map转为json写出去
    out.flush();
    out.close();
    }
    })
    .and()
    .csrf().disable();
    }

    Spring Security权限管理实例分析

    Spring Security权限管理实例分析

    4 多个HttpSecurity的配置

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

    @Configuration
    publicclassMultiHttpSecurityConfig{
    //暂且密码不加密
    @Bean
    PasswordEncoderpasswordEncoder(){
    returnNoOpPasswordEncoder.getInstance();
    }

    //配置用户名和密码
    @Autowired
    protectedvoidconfigure(AuthenticationManagerBuilderauth)throwsException{
    auth.inMemoryAuthentication()
    .withUser("LIFEILIN").password("LIFEILIN").roles("admin")//第一个
    .and()
    .withUser("123").password("123").roles("user");//第二个
    }

    @Configuration
    @Order(1)
    publicstaticclassAdminSecurityConfigextendsWebSecurityConfigurerAdapter{
    @Override
    protectedvoidconfigure(HttpSecurityhttp)throwsException{
    http.antMatcher("/admin/**").authorizeRequests().anyRequest().hasRole("admin");//admin角色访问
    }
    }

    @Configuration
    publicstaticclassOtherSecurityConfigextendsWebSecurityConfigurerAdapter{
    @Override
    protectedvoidconfigure(HttpSecurityhttp)throwsException{
    http.authorizeRequests().anyRequest().authenticated()
    .and()
    .formLogin()
    .loginProcessingUrl("/doLogin")
    .permitAll()
    .and()
    .csrf().disable();
    }
    }
    }

    5 密码加密

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

    @Test
    voidcontextLoads(){
    for(inti=0;i<10;i++){
    BCryptPasswordEncoderencoder=newBCryptPasswordEncoder();
    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&hellip;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

    Spring Security权限管理实例分析

    6 方法安全

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

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

    @Autowired
    MethodServicemethodService;

    @GetMapping("/hello1")
    publicStringhello1(){
    returnmethodService.admin();
    }
    @GetMapping("/hello2")
    publicStringhello2(){
    returnmethodService.user();
    }
    @GetMapping("/hello3")
    publicStringhello3(){
    returnmethodService.hello();
    }

    【Service层:】

    @Service
    publicclassMethodService{
    @PreAuthorize("hasRole('admin')")
    publicStringadmin(){//需要admin角色才能访问
    return"helloadmin";
    }

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

    @PreAuthorize("hasAnyRole('admin','user')")//admin,user两种权限
    publicStringhello(){
    return"hellohello";
    }
    }

    7 基于数据库的认证

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

    Spring Security权限管理实例分析

    Spring Security权限管理实例分析

    Spring Security权限管理实例分析

    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

    packagecom.example.bean;

    importorg.springframework.security.core.GrantedAuthority;
    importorg.springframework.security.core.authority.SimpleGrantedAuthority;
    importorg.springframework.security.core.userdetails.UserDetails;

    importjava.util.ArrayList;
    importjava.util.Collection;
    importjava.util.List;

    /*
    @author李飞林
    @ClassNameUser
    @mail1961785612@qq.com
    @DescriptionTODO
    @date2022/8/421:46
    */
    publicclassUserimplementsUserDetails{
    privateIntegerid;
    privateStringusername;
    privateStringpassword;
    privateBooleanenabled;
    privateBooleanlocked;
    privateList<Role>roles;

    publicList<Role>getRoles(){
    returnroles;
    }

    publicvoidsetRoles(List<Role>roles){
    this.roles=roles;
    }

    publicvoidsetId(Integerid){
    this.id=id;
    }

    publicvoidsetUsername(Stringusername){
    this.username=username;
    }

    publicvoidsetPassword(Stringpassword){
    this.password=password;
    }

    publicvoidsetEnabled(Booleanenabled){
    this.enabled=enabled;
    }

    publicvoidsetLocked(Booleanlocked){
    this.locked=locked;
    }

    publicIntegergetId(){
    returnid;
    }

    @Override
    publicStringgetUsername(){
    returnusername;
    }

    @Override
    publicbooleanisAccountNonExpired(){//账号是否未过期
    returntrue;
    }

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

    @Override
    publicbooleanisCredentialsNonExpired(){
    returntrue;
    }

    @Override
    publicbooleanisEnabled(){//是否可用
    returnenabled;
    }

    @Override
    publicCollection<?extendsGrantedAuthority>getAuthorities(){
    List<SimpleGrantedAuthority>authorities=newArrayList<>();
    for(Rolerole:roles){
    authorities.add(newSimpleGrantedAuthority("ROLE_"+role.getName()));//角色认证以ROLE_开始
    }
    returnauthorities;//返回用户所有角色
    }

    @Override
    publicStringgetPassword(){
    returnpassword;
    }
    }

    packagecom.example.bean;

    /*
    @author李飞林
    @ClassNameRole
    @mail1961785612@qq.com
    @DescriptionTODO
    @date2022/8/421:49
    */
    publicclassRole{
    privateIntegerid;
    privateStringname;
    privateStringnameZh;

    publicIntegergetId(){
    returnid;
    }

    publicvoidsetId(Integerid){
    this.id=id;
    }

    publicStringgetName(){
    returnname;
    }

    publicvoidsetName(Stringname){
    this.name=name;
    }

    publicStringgetNameZh(){
    returnnameZh;
    }

    publicvoidsetNameZh(StringnameZh){
    this.nameZh=nameZh;
    }
    }

    4、编写mapper层
    UserMapper接口:

    packagecom.example.mapper;

    importcom.example.bean.Role;
    importcom.example.bean.User;
    importorg.apache.ibatis.annotations.Mapper;

    importjava.util.List;

    /*
    @author李飞林
    @ClassNameUserMapper
    @mail1961785612@qq.com
    @DescriptionTODO
    @date2022/8/422:01
    */
    @Mapper
    publicinterfaceUserMapper{
    UserloadUserByUsername(Stringusername);

    List<Role>getUserRolesById(Integerid);
    }

    UserMapper.xml:

    <?xmlversion="1.0"encoding="UTF-8"?>
    <!DOCTYPEmapperPUBLIC"-//mybatis.org//DTDMapper3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;&gt;
    <mappernamespace="com.example.mapper.UserMapper">
    <selectid="loadUserByUsername"resultType="com.example.bean.User">
    select
    fromuser
    whereusername=#{username};
    </select>
    <selectid="getUserRolesById"resultType="com.example.bean.Role">
    select

    fromrole
    whereidin(selectridfromuser_rolewhereuid=#{id})
    </select>
    </mapper>

    5、编写service层:

    packagecom.example.service;

    importcom.example.bean.User;
    importcom.example.mapper.UserMapper;
    importorg.springframework.beans.factory.annotation.Autowired;
    importorg.springframework.security.core.userdetails.UserDetails;
    importorg.springframework.security.core.userdetails.UserDetailsService;
    importorg.springframework.security.core.userdetails.UsernameNotFoundException;
    importorg.springframework.stereotype.Service;

    /*
    @author李飞林
    @ClassNameUserService
    @mail1961785612@qq.com
    @DescriptionTODO
    @date2022/8/422:01
    */
    @Service
    publicclassUserServiceimplementsUserDetailsService{
    @Autowired
    UserMapperuserMapper;

    @Override
    publicUserDetailsloadUserByUsername(Stringusername)throwsUsernameNotFoundException{
    Useruser=userMapper.loadUserByUsername(username);
    if(user==null){
    thrownewUsernameNotFoundException("用户不存在");
    }
    user.setRoles(userMapper.getUserRolesById(user.getId()));
    returnuser;
    }
    }

    6、security安全配置:

    packagecom.example.config;

    importcom.example.service.UserService;
    importorg.springframework.beans.factory.annotation.Autowired;
    importorg.springframework.context.annotation.Bean;
    importorg.springframework.context.annotation.Configuration;
    importorg.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    importorg.springframework.security.config.annotation.web.builders.HttpSecurity;
    importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    importorg.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    importorg.springframework.security.crypto.password.PasswordEncoder;

    /*
    @author李飞林
    @ClassNameSecurityConfig
    @mail1961785612@qq.com
    @DescriptionTODO
    @date2022/8/422:35
    */
    @Configuration
    publicclassSecurityConfigextendsWebSecurityConfigurerAdapter{
    @Autowired
    UserServiceuserService;

    @Override
    protectedvoidconfigure(AuthenticationManagerBuilderauth)throwsException{
    auth.userDetailsService(userService);
    }

    @Bean
    PasswordEncoderpasswordEncoder(){
    returnnewBCryptPasswordEncoder();
    }

    @Override
    protectedvoidconfigure(HttpSecurityhttp)throwsException{
    http.authorizeRequests()
    .antMatchers("/dba/").hasRole("dba")
    .antMatchers("/admin/
    ").hasRole("admin")
    .antMatchers("/user/**").hasRole("user")
    .anyRequest().authenticated()//其他可访问
    .and()
    .formLogin()
    .permitAll()
    .and()
    .csrf().disable();
    }
    }

    7、controller层接口调试:

    packagecom.example.controller;

    importorg.springframework.web.bind.annotation.GetMapping;
    importorg.springframework.web.bind.annotation.RestController;

    /*
    @author李飞林
    @ClassNameHelloController
    @mail1961785612@qq.com
    @DescriptionTODO
    @date2022/8/422:40
    */
    @RestController
    publicclassHelloController{
    @GetMapping("/hello")
    publicStringhello(){
    return"hellosecurity";
    }

    @GetMapping("/dba/hello")
    publicStringdba(){
    return"hellodba";
    }

    @GetMapping("/admin/hello")
    publicStringadmin(){
    return"helloadmin";
    }

    @GetMapping("/user/hello")
    publicStringuser(){
    return"hellouser";
    }
    }

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

    //角色继承
    @Bean
    RoleHierarchyroleHierarchy(){
    RoleHierarchyImplroleHierarchy=newRoleHierarchyImpl();
    Stringhierarchy="ROLE_dba>ROLE_admin>ROLE_user";//dba>admin>user
    roleHierarchy.setHierarchy(hierarchy);
    returnroleHierarchy;
    }

    9 动态配置权限

    数据库中的表结构如下:

    Spring Security权限管理实例分析

    Spring Security权限管理实例分析

    Spring Security权限管理实例分析

    Spring Security权限管理实例分析

    Spring Security权限管理实例分析

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

    Spring Security权限管理实例分析

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

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

    @Override
    publicCollection<?extendsGrantedAuthority>getAuthorities(){
    List<SimpleGrantedAuthority>authorities=newArrayList<>();
    for(Rolerole:
    roles){
    authorities.add(newSimpleGrantedAuthority(role.getName()));
    }
    returnauthorities;
    }

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

    @Service
    publicclassUserServiceImplextendsServiceImpl<UserMapper,User>implementsUserService,UserDetailsService{
    @Autowired
    UserMapperuserMapper;

    @Override
    publicUserDetailsloadUserByUsername(Stringusername)throwsUsernameNotFoundException{
    Useruser=userMapper.loadUserByUsername(username); //根据登录字符串获获取用户名
    if(user==null){
    thrownewUsernameNotFoundException("用户不存在");
    }else{
    user.setRoles(userMapper.getRolesById(user.getId())); //根据用户名的ID查询所具有的角色
    }
    returnuser;
    }
    }

    3、编写UserMapper接口:

    @Mapper
    publicinterfaceUserMapperextendsBaseMapper<User>{

    UserloadUserByUsername(Stringusername);

    List<Role>getRolesById(Integerid);
    }

    4、编写UserMapper.xml:

    <selectid="loadUserByUsername"resultType="com.lifeilin.pojo.User">
    select*
    fromuser
    whereusername=#{username}
    </select>

    <selectid="getRolesById"resultType="com.lifeilin.pojo.Role">
    select*
    fromrole
    whereidin(selectridfromuser_rolewhereuid=#{id});
    </select>

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

    二、配置SecurityConfig

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

    @Configuration
    publicclassSecurityConfigextendsWebSecurityConfigurerAdapter{
    @Autowired
    UserServiceImpluserService;

    @Bean
    PasswordEncoderpasswordEncoder(){
    returnnewBCryptPasswordEncoder();
    }

    //配置登录

    @Override
    protectedvoidconfigure(AuthenticationManagerBuilderauth)throwsException{
    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

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

    Spring Security权限管理实例分析

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

    @Service
    @CacheConfig(cacheNames="c1")
    publicclassMenuServiceImplextendsServiceImpl<MenuMapper,Menu>implementsMenuService{
    @Autowired
    MenuMappermenuMapper;

    //可以加缓存
    @Cacheable
    publicList<Menu>getAllMenus(){
    returnmenuMapper.getAllMenus();
    }
    }

    @Mapper
    publicinterfaceMenuMapperextendsBaseMapper<Menu>{

    List<Menu>getAllMenus();
    }

    <?xmlversion="1.0"encoding="UTF-8"?>
    <!DOCTYPEmapperPUBLIC"-//mybatis.org//DTDMapper3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;&gt;
    <mappernamespace="com.lifeilin.mapper.MenuMapper">
    <!--查询所有menu-->
    <!--resultMap:填入配置的resultMap标签的id值-->
    <selectid="getAllMenus"resultMap="BaseResultMap">
    SELECTm.id,
    m.pattern,
    r.idASrid,
    r.NAMEASrname,
    r.nameZhASrnameZh
    FROMmenuASm
    LEFTJOINmenu_roleASmrONm.id=mr.mid
    LEFTJOINroleASrONmr.rid=r.id
    </select>
    <!--resultMap最终还是要将结果映射到pojo上,type就是指定映射到哪一个pojo-->
    <resultMapid="BaseResultMap"type="com.lifeilin.pojo.Menu">
    <!--定义主键,非常重要。如果是多个字段,则定义多个id-->
    <!--property:主键在pojo中的属性名-->
    <!--column:主键在数据库中的列名-->
    <idproperty="id"column="id"></id>
    <!--定义普通属性-->
    <resultproperty="pattern"column="pattern"></result>
    <!--collection中property的roles对应的是Role实体中的属性-->
    <collectionproperty="roles"ofType="com.lifeilin.pojo.Role">
    <idcolumn="rid"property="id"/>
    <resultcolumn="rname"property="name"/>
    <resultcolumn="rnameZh"property="nameZh"/>
    </collection>
    </resultMap>
    </mapper>
    @Component
    publicclassMyFilterimplementsFilterInvocationSecurityMetadataSource{
    //路径匹配符
    AntPathMatcherpathMatcher=newAntPathMatcher();

    @Autowired
    MenuServiceImplmenuService;

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

    @Override
    publicCollection<ConfigAttribute>getAllConfigAttributes(){
    returnnull;
    }

    @Override
    publicbooleansupports(Class<?>clazz){
    returntrue;
    }
    }

    2、在config包中创建MyAccessDecisionManager类

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

    @Component
    publicclassMyAccessDecisionManagerimplementsAccessDecisionManager{
    @Override
    publicvoiddecide(Authenticationauthentication,Objectobject,Collection<ConfigAttribute>configAttributes)throwsAccessDeniedException,InsufficientAuthenticationException{//authentication知道有哪些角色,configAttributes知道需要哪些角色
    //1、遍历需要的角色
    for(ConfigAttributeattribute:configAttributes){
    if("ROLE_login".equals(attribute.getAttribute())){//请求地址都没匹配上,说明是登陆后就可访问的请求地址
    if(authenticationinstanceofAnonymousAuthenticationToken){//匿名用户(没登陆)
    thrownewAccessDeniedException("非法请求");
    }else{
    return;
    }
    }
    //2、获取所具备的角色
    Collection<?extendsGrantedAuthority>authorities=authentication.getAuthorities();
    for(GrantedAuthorityauthority:authorities){
    if(authority.getAuthority().equals(attribute.getAttribute())){//如果具备所需要的角色
    return;
    }
    }
    }
    thrownewAccessDeniedException("非法请求");
    }

    @Override
    publicbooleansupports(ConfigAttributeattribute){
    returntrue;
    }

    @Override
    publicbooleansupports(Class<?>clazz){
    returntrue;
    }
    }

    3、在SecurityConfig引入myAccessDecisionManager + myFilter

    @Override
    protectedvoidconfigure(HttpSecurityhttp)throwsException{
    http.authorizeRequests()
    .withObjectPostProcessor(newObjectPostProcessor<FilterSecurityInterceptor>(){
    @Override
    public<OextendsFilterSecurityInterceptor>OpostProcess(Oobject){
    object.setAccessDecisionManager(myAccessDecisionManager);//
    object.setSecurityMetadataSource(myFilter);//
    returnobject;
    }
    })
    .and()
    .formLogin()
    .permitAll()
    .and()
    .csrf().disable();
    }
    若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

    本文:Spring Security权限管理实例分析的详细内容,希望对您有所帮助,信息来源于网络。
    上一篇:C语言函数之memcpy函数怎么使用下一篇:

    18 人围观 / 0 条评论 ↓快速评论↓

    (必须)

    (必须,保密)

    阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18