Spring Security in conjuction with Spring repositories to secure and authenticate various parts of a website

江枫思渺然 提交于 2019-12-20 05:11:41

问题


I was looking for a concrete, serious and complete example on how to use Spring security in a Spring Boot application that uses Spring data repositories to access the database and therefore to query about registered users.

I've seen that it's easily protected a range of webpages using Spring security by overriding the configure method, for example with the following options:

http.authorizeRequests()
    .antMatchers("/", "/css/**", "/js/**", "/vendor/**", "/templates/**")
    .permitAll()
    .anyRequest()
    .authenticated()
    .and()
    .formLogin()
    .loginPage("/login")
    .permitAll()
    .and()
    .logout()
    .permitAll();

This code protects users for example from accessing http://localhost:3000/home/users/, but allows then to access http://localhost:3000/login or simply http://localhost:3000.

I've been reading around about Spring security, but I can't get how can I protect the different parts of an application, for example, when a user has logged in to the website, and prohibit him from accessing from example http://localhost:3000/home/users/another_user, and in general to control the access of a logged user to all parts of the website.

I'm using Spring data repositories to manipulate data of the database through the entities.

Do you know about an example that uses Spring security in conjunction with Spring repositories (and if necessary other tools) to protect (and authenticate) different parts of a website? A (video-)tutorial may also be useful.

Thanks for any help.

Note: I've looked at the sagan website's repository, but it's quite complex to understand what's going on...


回答1:


This is called Access Control, or "Domain Object Security" in Spring Security.

http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#domain-acls

You've got a lot of reading to do!

You probably want to combine it with Spring Data JPA, so that SDJ only returns the records it should. An example here:

https://github.com/spring-projects/spring-data-examples/tree/master/jpa/security

Basically you're going to be adding some "row owner" info to your tables, and getting SDJ and SS to work together to control access, like:

@Query("select o from BusinessObject o where o.owner.emailAddress like ?#{hasRole('ROLE_ADMIN') ? '%' : principal.emailAddress}")
List<BusinessObject> findBusinessObjectsForCurrentUser();

An alternative it to use a database server that supports Row Security, like PostgreSQL, and handle your access control right in the db.




回答2:


As noted above ACLs are one option however an alternative and possibly simpler solution may to be to apply security at the method level.

See section 15.3.

https://docs.spring.io/spring-security/site/docs/3.0.x/reference/el-access.html

So supposing you have an URL /users/123 where 123 is the current user and which delegates to a service layer method to load the user then how do I prevent the user from tampering with the URL and seeing data returned by e.g. /users/456.

One approach is to apply method level security via the @PostAuthorize annotation:

@PostAuthorize("hasPermission(returnObject, null)")
public User findById(Long id) {
    return repository.findOne(id);
}

The security checks are delegated to an implementation of org.springframework.security.access.PermissionEvaluator

An implementation could look like the below:

public class BasePermissionsEvaluator implements PermissionEvaluator {

    public boolean hasPermission(Authentication authentication, Object domainObject) {
        return hasPermission(authentication, domainObject, null);
    }

    @Override
    public boolean hasPermission(Authentication authentication, Object domainObject, Object permission) {
        boolean hasPermission = true;

        //User is my custom class representing a logged in user
        //UserEntity is my custom interface implemented by entities associated with specific user
        //If user is an Admin allow access
        //Otherwise allow access if logged in user 'owns' the DomainObject instance
        User user = (User) authentication.getPrincipal();

        if(! user.isAdmin()){
            if (domainObject instanceof UserEntity) {
                User owner = ((UserEntity) domainObject).getOwner();
                hasPermission = user.equals(owner);
            }
        }

        return hasPermission;
    }

    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType,
            Object permission) {
        return false;
    }
}

Configuration of the PermissionEvaluator looks like the following in XML so you would need to convert to Java config:

<security:global-method-security
    pre-post-annotations="enabled">
        <security:expression-handler ref="expressionHandler"/>
</security:global-method-security>

<bean id="expressionHandler"
    class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
    <property name="permissionEvaluator" ref="permissionEvaluator" />
</bean>

<bean id="permissionEvaluator" class="com.mycompany.BasePermissionsEvaluator" />

The following outlines converting the XML config to Java config:

https://spring.io/blog/2013/07/04/spring-security-java-config-preview-method-security/#custom-method-security

So in your existing security configuration class it looks like you would add:

@EnableGlobalMethodSecurity(prePostEnabled=true) //ADD THIS
public class MySecurityConfig{

  @Override
  protected MethodSecurityExpressionHandler expressionHandler() {
    DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();

    //SET TO OUR CUSTOM PERMISSIONS HANDLER DETAILED ABOVE
    expressionHandler.setPermissionEvaluator(new BasePermissionsEvaluator());

    return expressionHandler;
  }
}


来源:https://stackoverflow.com/questions/37057175/spring-security-in-conjuction-with-spring-repositories-to-secure-and-authenticat

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!