ChatGPT解决这个技术问题 Extra ChatGPT

What's the "principal" in Spring Security?

I'm really new to Spring and Spring Security. I was reading about Spring Security and it came out the concept of principal, which should be the current logged user. But what if we have more than one current logged user? So, my question is, what exactly is then the principal in spring security?

I've read for example this tutorial:

http://www.mkyong.com/spring-security/get-current-logged-in-username-in-spring-security/

and they seem to take into account that there's just one current logged user, which isn't often the case.

How do I retrieve a specific user? And how do I differentiate between users that are doing requests?


M
Marcel Stör

The principal is the currently logged in user. However, you retrieve it through the security context which is bound to the current thread and as such it's also bound to the current request and its session.

SecurityContextHolder.getContext() internally obtains the current SecurityContext implementation through a ThreadLocal variable. Because a request is bound to a single thread this will get you the context of the current request.

To simplify you could say that the security context is in the session and contains user/principal and roles/authorities.

How do I retrieve a specific user?

You don't. All APIs are designed to allow access to the user & session of the current request. Let user A be one of 100 currently authenticated users. If A issues a request against your server it will allocate one thread to process that request. If you then do SecurityContextHolder.getContext().getAuthentication() you do so in the context of this thread. By default from within that thread you don't have access to the context of user B which is processed by a different thread.

And how do I differentiate between users that are doing requests?

You don't have to, that's what the Servlet container does for you.


So, my consequent question is: how does spring differentiate between sessions, and users? I guess this requires a deeper understanding of Spring...
Thanks! Nice answer. I have just one doubt which comes from my reduced experience in creating web applications, etc. But before let me try to explain what I think I know. From what I've learnt, HTTP requests can be enhanced with a session IDs. This information is probably used by Tomcat (or whatever) to differentiate between users and requests. Principal is the current logged in user for the current context. To understand that there's a logged in user (a principal), a session number must probably be associated with it.
Now, suppose that I've two logged in users called root and admin and I've a controller whose request mapping is /users/{username}. Suppose further that root is playing with his account on the client side at the URL www.host.com:3000/users/root. At this point, I guess a session ID has already been generated for root. If it now tries to do a request to www.host.com:3000/users/admin, by changing for example the URL manually, and admin is also connected and logged in from another machine, what would happen in this case?
I guess this would not be allowed by the server because the request does probably not contain the right information, i.e. the right session id?
@nbro With RestController just need to add the Principal arg like here, Spring will automatically populate it, and you can do whatever security checking desired. (e.g., if P is "root" but is trying to see "admins" page throw a 403 error but allow it he's trying to his page.) See Section 15.3.2.3 here for all the arguments you can choose that Spring will populate for you automatically.
O
Ousama

Brief definition of Principal:

A Principal represents a user's identity.

It can be a String object having username on a simple level or a complex UserDetails object.


P
Panagiotis Bougioukos

Principal is just an old interface from Java SE 6.

As all interfaces without default implementation it simple defines some methods which are required to be implemented by the class which will implement that interface.

Those methods are

boolean  equals(Object another)
          Compares this principal to the specified object.

String   getName()
          Returns the name of this principal.

int      hashCode()
          Returns a hashcode for this principal.

String   toString()
          Returns a string representation of this principal.

As the Java Doc states :

This interface represents the abstract notion of a principal, which can be used to represent any entity, such as an individual, a corporation, and a login id.

In simple terms it is just used so that the implementer will have to implement this interface in a way that he makes an entity uniquely distingueed between other entities. Also the getName() will have to return a value by which one specific entity is uniquely identified and does not collide with other entities. So if the Principal which is used is of type UserDetails then the getName() of Principal returns the UserName of UserDetails.

If we see the implementation that Spring uses for AbstractAuthenticationToken.class :

public String getName() {
        if (this.getPrincipal() instanceof UserDetails) {
            return ((UserDetails)this.getPrincipal()).getUsername();
        } else if (this.getPrincipal() instanceof AuthenticatedPrincipal) {
            return ((AuthenticatedPrincipal)this.getPrincipal()).getName();
        } else if (this.getPrincipal() instanceof Principal) {
            return ((Principal)this.getPrincipal()).getName();
        } else {
            return this.getPrincipal() == null ? "" : this.getPrincipal().toString();
        }
    }

Also is important to mention:

abstract class AbstractAuthenticationToken implements Authentication and

interface Authentication extends Principal

Principal Interface also ensures that the implementer will implement equals() and hashCode() which makes much sense because the entity of Principal that represents an Organization or a Company or a Person must have some way of being compared with other entities.