简体   繁体   中英

Using intercept-url in Spring security

What is the preferred way of making patterns in the intercept-url element in Spring security? I am creating a web service (RESTful) and I currently require that all users are logged in and have the role ROLE_USER . Then further constraints are enforced by @PreAuthorize annotations on the service layer. However is it common to also add multiple intercept-url elements that have different configuration?

I should think that "the preferred way" is [necessarily] subjective. I had <intercept-url> elements in my security.xml , but abandoned them in favor of @RequestMapping annotations with @PreAuthorize on the controllers. It's purely personal preference (in my case), as I favor keeping things in Java rather than in XML namespaces, as much as it is possible to do so.

You can use one, the other, or both, and you can make the annotation enhance the XML -- you can, for example have something like the following:

security.xml :

<intercept-url pattern="/something" access="hasRole('ROLE_USER')"/>

YourController.java :

@RequestMapping(value="/something/else")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public String getSomethingElseContents(){ return "somethingelse"; }

As I said, it seems like it's merely a matter of preference. The benefit to using the XML namespace is that the base access rules are all in one place, easy to read, and easy to follow. The rules imposed by @PreAuthorize (or the other annotation variants) are particularly sexy because you can call your own SpEL expression in them, and base your permission decision on access to parameters passed or fields accessible by the class (ie @PreAuthorize("@my.project.package.hasMagicPower(#power.INVISIBILITY)") ), or combinations of these. You can apply logic and dynamic permissions which are otherwise unavailable to the namespace option.

Of course you can apply rudimentary logic with the 'and', 'or' and '!' connectives in SpEL expressions in the namespace (and you may be able to access external class [boolean] methods via the @ designator in the XML), but everything specified in the XML must be static.


tl;dr : Personal preference is preference, but if you want or need dynamic flexibility in your permission handling, you have to use annotations. If you neither want nor need dynamic flexibility, you have the option (and a sound argument would suggest that the namespace option is better with respect to SoC). I prefer letting the Java handle it for the flexibility and because once I set up my XML, I want to leave it the hell alone and focus on the Java. Also, there is a somewhat convincing counterargument to the SoC view, which is that a properly conventionalized Java application will have its controllers in easy-to-find packages with obvious-by-name control.


still tl;dr : Meh. Six of one, half a dozen of the other. I say po-tay-to.

Most web applications using Spring Security only have a couple of intercept-url s because they only have very basic security requirements. You need to have unauthenticated access to the login and login-error screens and usually some aspect of the public site, so that can be a few URL patterns. Then there's often an admin section, and then everything else is ROLE_USER .

If you need more roles, it's customary to associate them with top level URL path components. Although it's not required, it makes it easier to be sure that resources are appropriately protected.

<http realm="Contacts Realm" use-expressions="false">
    <intercept-url pattern="/index.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    <intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    <intercept-url pattern="/admin/*" access="ROLE_ADMIN"/>
    <intercept-url pattern="/secret/*" access="ROLE_SECRET"/>
    <intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN,ROLE_SECRET"/>
    <http-basic/>
</http>

You have to decide, based on your use cases, whether you want to allow people to have multiple roles. It's a bit harder to manage in the app, so most people with simple security set it up so that users have exactly one role and then they allow multiple roles to access protected content. The other way to do it, of course, is one role per URL pattern and give people multiple roles.

Anyway, the answer to your question (or to at least the question I think you are asking) is that the usual thing to do is one top-level path component per role protecting all resources with the same security restrictions. Of course, you are also grouping functionality under that path prefix, so some people hate this structure and some people just prefer to use annotations in the code. I like my security where I can see it in one place and can easily tell what the security expectation is just by looking at the URL.

The configuration of SpringSecurity depends on the authentication you select for your application: For example, for the Form Authentication you want to configure the login url and logout success url without permissions:

<http realm="Contacts Realm">
    <intercept-url pattern="/index.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    <intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    <intercept-url pattern="/**" access="ROLE_USER"/>
    <form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error=1"/>
    <logout logout-success-url="/index.jsp"/>
</http>

In case of Basic Authentication you do not have the login and logout URLs and the configuration is simpler:

<http realm="Contacts Realm">
    <intercept-url pattern="/**" access="ROLE_USER"/>
    <http-basic/>
</http>

In case you will select Basic authentication use the second example.

Intercepting URL's can be done this way. Suppose your rest service URLs start with /rest/ .

<http auto-config="true" use-expressions="true" access-denied-page="/accessDeniedPageURL">
    <intercept-url pattern="/rest/**" access="hasRole('ROLE_USER')"/>
    <intercept-url pattern="/view/products" access="isFullyAuthenticated()"/>        

    <form-login login-page="/landing" default-target-url="/view/products" authentication-failure-handler-ref="authenticationFailureHandler"/>
    <logout invalidate-session="true" logout-success-url="/landing" delete-cookies="JSESSIONID"/>

    <session-management invalid-session-url="/landing" session-authentication-error-url="/landing?msg=alreadyLogin">
        <concurrency-control max-sessions="1" expired-url="/landing?msg=sessionExpiredDuplicateLogin" error-if-maximum-exceeded="false"/>
    </session-management>    
</http>

Yes it's quite common to define multiple intercept-url patterns and then add annotations on top to further restrict particular resources.

You can also use a directory for each restriction so that way you won't need annotations. Ex. /user/** requires ROLE_USER, /admin/** requires ROLE_ADMIN, etc.

Keep in mind when using either method how it affects your security in case you make a mistake.

If using intercept url, you must put the lines in the correct order, for example:

<intercept-url pattern="/**" access="permitAll"/>
<intercept-url pattern="/user/**" access="hasRole('ROLE_USER')"/>

Will not work, because you're grating all access in the first line, so the lines have to be reversed. If a beginner is working on your project and reverses the lines, it could be a big issue.

If you use annotations, you can delete the annotation line by mistake, leaving a security hole in your application.

@PreAuthorize("hasRole('ROLE_USER')")

If you are re-using a controller class between two projects, and in one project you want to allow ROLE_USER to all methods inside the controller, while the other project using the common code requires ROLE_ADMIN, then the easiest way to achieve that is to use intercept-url.

So keep in mind, @PreAuthorize will be hard-coded and shared among projects. You can extend the classes and add different @PreAuthorize for each project, but it adds extra complexity.

I like to use intercept-url to secure an entire area, like /user/**, because there is less risk of removing an annotation by mistake.

If I need to add fine-grain access, I add an annotation to the method in the controller that is already secured by intercept-url, but this happens very rarely.

Spring Security is generally good for Role based access. and that's about it. You could create your own ProcessingFilter to do some additional things. However, i find that this is a lot of work for little benifit.

The alternative, is to use Request Interceptors. On several projects for RESTful services using Spring MVC, I utilize Request Interceptors to finalize some authentication beyond the basic Role access. This works, and in my opinion makes the chain of events much easier to follow, but if you're dealing with thousands of transactions per minute, it could bog down the requests.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM