The most basic authentication scheme looks like this:
- Client knows password.
- Client shows password to server.
- Server is happy.
Password hashing is done only to counter a secondary threat: that some bad guy succeeds at having a peek at the server files or database, through some illicit but common way (SQL injection attacks are usual). We don't want that bad guy to immediately learn all the user passwords. That would be inappropriate. To avoid that, the server will not store the passwords themselves, but only some values which are sufficient to verify a password. This is where hashing occurs. The server hashes the passwords, with a slow and salted hash function, so that the envisioned attacker with sharp eyes will at least have to perform some substantial work for each password he will recover.
But that hashing is entirely a server business. The client does not see it. From the point of view of the client, the protocol is just "show the password". How the server decides that the password is the correct one or not, is completely irrelevant to the client.
The basic protocol is usually sufficient because it will be played within SSL (aka HTTPS in a Web context), which ensures that the client has some a priori guarantee that it is sending the password to the right server, and nobody else can spy on it. We need something like SSL anyway, to prevent the connection from being commandeered once the authentication has been done. So we might as well use it and just show the password to the server.
Nevertheless, some other protocols have been designed, in which the raw password is not shown to the server. Motivation is either distrust of the security guarantees provided by SSL and its digital certificates, or just disregard of the risks of hostile hijacking (the protocol is played "in the clear" and it is just assumed that attackers are passive only -- a singularly optimistic stance, verging on the naivety, but it was much more common in the late 1980s and early 1990s). These are challenge-response authentication protocols. Your proposal with the "encrypted blob" is of that kind. The server sends a value to the client (the challenge) and expects the client to process it in some way which involves the password (that's your "decryption"). The server verifies that the client properly responded to the challenge.
In general, challenge-response protocols are not a good idea. They have the following drawbacks:
The main benefit of a challenge-response protocol is to avoid showing the password to a fake server. But showing the password to a fake server occurs only if the client accepts to talk to a fake server in the first place, meaning that the transport medium can be subverted and allows replay attacks and men-in-the-middle. This is bad news. The overall situation is rotten and should be fixed in a much more thorough way than using a challenge-response protocol. Wearing a lifejacket is good, not being on board the Titanic is better.
The server must have a way to verify the response to the challenge. It is very hard for the server to avoid storing something which is password-equivalent. For instance, if the challenge is "you, client, decrypt this blob !", then the server must have encrypted some data to produce the challenge blob; otherwise, how would the server know that the decryption worked ? And to do the encryption, the server must know the encryption key, i.e. the password, not a hashed version thereof. You have lost the benefits of slow and salted hashing. Keeping the server's database invisible from the attackers becomes critical again.
If the server is fake (and you are using a challenge-response protocol instead of just show-the-password precisely because you deem it possible that the server is fake), then that fake server will still learn a value which is deterministically computed from the password, i.e. something which is sufficient to mount an offline dictionary attack (the bad guy tries potential passwords at the full speed of his GPU, on his own machines). That's not good. (Speaking of which, your suggestion to use the "hash of the user password concatenated with the username" as salt is not a salt at all, because of this determinism.)
A client who responds to a challenge is a client who can compute. This does not map well to a Web context. In a Web context, client code is Javascript, and Javascript is feeble; it is not good at computationally intensive tasks.
These drawbacks can be fixed, with another tool: mathematics. Maths are great. They allow a more recent and considerably niftier class of authentication protocols, called password authenticated key exchange. These protocols allow for mutual authentication (the client also gains some guarantee that it talks to the right server; they resist offline dictionary attacks (even a fake server, or a fake client for that matter, does not learn anything which would be sufficient for that), and the best of them avoid having to store server-side some password-equivalent data. The most oft-cited PAKE protocol is SRP. SRP has the additional benefit of being integrated in SSL/TLS, which is good because even with the best authentication protocol in the world, you still need something to protect whatever data you will send afterwards.