【问题标题】:Spring Security URL based authorization基于 Spring Security URL 的授权
【发布时间】:2019-06-27 06:53:36
【问题描述】:

我想在我的一个 spring mvc 项目中实现基于 URL 的授权。在我的 spring mvc 项目中,我使用的是 java 配置。我参考了这个站点https://www.baeldung.com/role-and-privilege-for-spring-security-registration 来实现基于角色和权限的授权。

所以我创建了以下表格来实现。

这是用户表。

这个角色表。

这是角色和权限的映射表。

这是权限表。

以下是控制器端的代码。

@Controller
@RequestMapping(value={"/user"})
public class UserController {

    @ResponseBody
    @RequestMapping(value={"/userDashboard"},method = RequestMethod.GET)
    public String userDashboard(ModelMap model){
        return "UserDashboard";
    }

    @ResponseBody
    @RequestMapping(value={"/testUser"},method = RequestMethod.GET)
    public String testUser(ModelMap model){
        return "TestUser";
    }

}

以下是实现 UserDetailService 的代码。

@Service("authService")
@Transactional
public class AuthService implements UserDetailsService {

    @Autowired
    private UserDaoInterface userDaoInterface;

    private static final Logger log = Logger.getLogger(AuthService.class);

    @Override
    public UserDetails loadUserByUsername(String userName) {
        User user = null;
        try {
            user = userDaoInterface.getUserByUserName(userName);
        } catch (Exception e) {
            log.error("AuthService @loadUserByUsername --Exception while fetching user from username",e);
        }

        if(user == null) {
            throw new UsernameNotFoundException("Username not found");
        }

        UserDetails userDetails = new org.springframework.security.core.userdetails.User(user.getUsername(),
                user.getPassword(),!user.getIsDeleted(),true,true,true,getAuthorities(user.getRole()));

        log.info("UserService userDetails " + userDetails);

        return userDetails;
    }

    private Collection<? extends GrantedAuthority> getAuthorities(Role role) {  
        return getGrantedAuthorities(getPrivileges(role));
    }

    private List<String> getPrivileges(Role role) {
        List<String> privileges = new ArrayList<>();
        List<Privilege> collection = new ArrayList<>();
        collection.addAll(role.getPrivileges());
        for (Privilege item : collection) {
            privileges.add(item.getName());
        }
        return privileges;
    }

    private List<GrantedAuthority> getGrantedAuthorities(List<String> privileges) {
        List<GrantedAuthority> authorities = new ArrayList<>();
        for (String privilege : privileges) {
            authorities.add(new SimpleGrantedAuthority(privilege));
        }
        return authorities;
    }
}

Spring 安全配置

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
@ComponentScan("com.project")
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService authService;

    @Autowired
    PersistentTokenRepository tokenRepository;

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

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

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

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(authService);
        authenticationProvider.setPasswordEncoder(passwordEncoder());
        return authenticationProvider;
    }

    @Bean
    public PersistentTokenBasedRememberMeServices getPersistentTokenBasedRememberMeServices() {
        return new PersistentTokenBasedRememberMeServices("remember-me", authService, tokenRepository);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
         http.authorizeRequests().anyRequest().authenticated()
         .and()
        .formLogin()
        .loginProcessingUrl("/login")
        .defaultSuccessUrl("/login")
        .and()
        .logout().logoutUrl("/logout")
        .logoutSuccessUrl("/")
        .and().csrf()
        .and().rememberMe().rememberMeParameter("remember-me").tokenRepository(tokenRepository).tokenValiditySeconds(86400);
    }
}

当我通过存储在用户表中的凭据登录系统并尝试访问像 http://localhost:8080/RestProject/user/testUser 这样的 url 时,用户有权访问此 url,但根据上述实现,用户不应被允许访问此 url。所以我无法理解动态权限在这里是如何工作的?

【问题讨论】:

  • 您的 Spring Security 配置在哪里?暴露一个UserDetailsService是不够的。
  • 这个应该在Spring Security Configuration中配置。
  • @Supun Dharmarathne 如果它应该在 Spring 安全配置中,那么在 UserDetailService 中的 getAuthorities 方法中上述实现的含义是什么。
  • @Supun Dharmarathne 我明白了为什么我们需要在 spring 安全配置中进行一些配置。所以我需要在 spring 安全配置中添加类似 .antMatchers("/user/userDashboard").hasRole("Admin") 的代码。有没有办法只注册登录用户的权限,而不是使用antMatchers注册所有角色的权限?
  • @HimanshuPatel 您配置了所有登录用户都可以访问http://localhost:8080/RestProject/user/testUser。因此,您的配置按预期工作。

标签: spring spring-mvc spring-security


【解决方案1】:

要配置url授权,您需要更改http.authorizeRequests().anyRequest().authenticated()这一行

到

http.authorizeRequests() .antMatchers("someurl").hasAuthority("ROLE_SOMEROLE") .antMatchers("/**").hasAuthority("ROLE_ADMIN").authenticated()

但是,您似乎想要让这些在运行时动态更改。我不确定春天是否让你这样做。但是,您可以通过对角色结构的设计进行一些更改来实现类似的行为。

您需要为您的权限添加一个分组层,并使这些组成为您的用户角色(这些将分配给用户)。然后,您授予的权限将是分配给您的角色/分组的权限。这样您就可以动态更改这些组下的权限,而无需更改代码。

角色权限结构示例(伪java代码):

注意:角色和组是可以互换的

@Entity
public class Permission {

    private String name;

    private String description;

    ... // getters and setters
}

@Entity
public class Role {

   private String name;

   @ManyToOne
   private List<Permission> permissions;
   ... // getters and setters
}

首先,您需要有一个可以做某事的网址。假设它创建了一个新的员工记录。因此,您需要创建一个新的“createEmployee”权限并设置访问该 url 所需的权限。这里的想法是创建特定于它所保护的操作的权限。这样您以后就不必更改权限了。

http.authorizeRequests() .antMatchers("some-url").hasAuthority("createEmployee") .antMatchers("/**").hasAuthority("admin").authenticated()

现在您需要做的就是将“createEmployee”权限分配给其职责包括此操作的角色。例如,假设它是“hiringManager”角色/分组。

权限被分配给角色/分组的例子:

Role hiringManager = new Role("hiringManager");
Permission createPermission = permissionRepository.findByName("createPermission");
hiringManager.getPermissions().add(createPermission);

这仅用于说明目的。理想情况下,您的应用程序中有一个屏幕,可以让您在运行时创建组和权限。然后,您可以根据需要从组中分配或删除权限。

请注意,这只是技术方面的一种解决方案。话虽如此,即使它不符合您的需求,它也应该指导您提出您的业务需求。

希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-01
    • 2020-06-16
    • 2016-01-11
    • 2020-07-09
    • 2021-02-15
    • 2011-05-01
    • 2013-07-07
    相关资源
    最近更新 更多