📜 ⬆️ ⬇️

Angular and Spring authentication without Spring Security (Spring server)

Part 2. Server on Spring


What is this article about


In this article, I will explain how to write simple authentication without the help of ready-made solutions for this task. It can be useful for beginners who want to write their own AAA (Authentication, Authorization, and Accounting). Client repository on Angular and Server repository on Spring .


In this article I will make excerpts of the server-side code in Spring


Spring authentication server


Project structure


. └── backendspring ├── BackendspringApplication.java # Spring  ├── config │ ├── AppProperties.java │ ├── AuthAuthority.java #       │ ├── CorsFilterAdapter.java #  CORS │ ├── ErrorMessages.java │ ├── IAuthority.java #     │ ├── RequestConstants.java │ ├── DefendedAuthority.java #      │ └── SecurityConfig.java #  CORS  Spring Security ├── controller │ ├── AuthController.java #   │ └── ProtectedPingPongController.java #   ├── dao │ ├── BaseDao.java │ └── SecureUserDao.java # DAO        ├── exception │ ├── AuthException.java │ └── PingPongException.java ├── function │ ├── BaseHandlerFunc.java #       ModelHandlerFunc.java │ ├── TrustedHandlerFunc.java #       │ └── SecureHandlerFunc.java #       ├── model │ ├── Answer.java #   -   │ ├── AuthUser.java #        │ ├── BaseDomain.java │ ├── EnumAuthority.java # Enum      │ ├── MessagePayload.java │ ├── MessageResponse.java │ ├── Payload.java #      /  JSON │ ├── PingPayload.java # ,     │ ├── PongPayload.java # ,    │ ├── UserCredentials.java #   /  │ └── SecureUser.java #       └── service ├── PingPongService.java # ,         ├── SecureUserService.java # ***,     /*** └── SecureUtils.java #      

Authentication / Authorization / Registration Service (SecureUserService)


SecureUserService main service of this article - for the sake of what she thought.


It implements the following methods:


public Optional<AuthUser> register(UserCredentials usercredentials) - User registration;


public Optional<AuthUser> authorize(UserCredentials usercredentials) - Authorization or user login;


public Optional<AuthUser> authenticate(AuthUser authUser) - Authentication or User Rights Verification;


public Optional<AuthUser> logout(AuthUser authUser) - public Optional<AuthUser> logout(AuthUser authUser) or Delete information that a user is currently online.


I will give the user authorization code:


 //      String credentials = usercredentials.getCredentials(); String salt = secureUser.getSalt(); String clientDigest = SecureUtils.digest(credentials + salt); //         if (clientDigest.equals(secureUser.getDigest())) { //   AccessToken      SecureUser TokenPair accessToken = getAccessToken(secureUser); //    String userSession = getUserSession(); //  AccessToken   secureUser.setSecureToken(accessToken.secureToken); secureUser.setAccessToken(accessToken.accessToken); secureUser.setUserSession(userSession); secureUserDao.save(secureUser); //  AccessToken,       String userId = secureUser.getId(); Set<EnumAuthority> authorities = secureUser.getAuthorities(); AuthUser authUser = AuthUser.simpleUser(userId, username, accessToken.accessToken, userSession, authorities); return authUser; } 

In general, the standard algorithm.


Yes, I do not use any user data to get AccessToken. I just generate a random string and encrypt it with standard javax.crypto encryption algorithms.


Client Authorization Controller (AuthController)


To form a response to the client, I used the method described earlier in this article.


In this example, I made some simplifications. But, here, functional interfaces from Java SE 8 are still used:


I will give an example of how I respond to a client's request after authorizing it on the site:


 @PostMapping("authorize") public @ResponseBody Answer authorize(@RequestBody UserCredentials usercredentials, HttpServletResponse response) { //       return ((TrustedHandlerFunc<UserCredentials>) (data) -> secureUserService.authorize(data) .map(Answer::ok) .orElseGet(Answer::forbidden)) .handleAuthRequest(response, usercredentials); } 

To handle unauthorized requests, I use the TrustedHandlerFunc functional interface. It contains the Answer process(T data) method. This method is implemented in the controller and it calls the SecureUserService::authorize method. The response of this service is glued to the Answer::ok method in case of successful authorization or the Answer::forbidden method in case of unsuccessful authorization. Also, the interface has a default method TrustedHandlerFunc::handleRequest and TrustedHandlerFunc::handleAuthRequest , which select Answer process(T data) for the Answer process(T data) method. Here is the UserCredentials . It is necessary to clarify that the first method handleRequest assumes the presence of the AuthUser token, and the second, handleAuthRequest , is needed only for the AuthController controller.


Client request processing controller (ProtectedPingPongController)


Consider a custom query handler. Call it PingPongService . By convention, this controller should not be accessible to unauthorized clients.


I will give an example of creating a response to a ping request:


 @PostMapping("ping") public @ResponseBody Answer ping(@RequestBody PingPayload ping, HttpServletRequest request, HttpServletResponse response) { return authenticateRequestService .getAuthenticatedUser(request, DefendedAuthority.PING) .map(authUser -> //    ((TrustedHandlerFunc<PingPayload>) (data) -> pingPongService.getPong(data, authUser) //      .map(Answer::ok) .orElseGet(Answer::forbidden) ).handleRequest(response, ping, authUser) //   ).orElseThrow(AuthException::forbidden); } 

It uses two functional interfaces: SecureHandlerFunc and TrustedHandlerFunc . The first one checks the custom headers that come from the client, creates an AuthUser "token" from them, and passes them to the next method of the TrustedHandlerFunc interface. Here, the token is expected to be an authorized user.


I will not give the details of the implementation of these interfaces, since they are already described in the article mentioned earlier. Let me just say that the only difference is in the division of duties on the authorization of the data received in the headers and sending the result to the client.


Not without Spring Security


It should be noted that still had to connect Spring Security to work with CORS.


To add the necessary headers, the code with StackOverflow was used and slightly reworked. It is in the CorsFilterAdapter and SecurityConfig classes.


Conclusion


In this article, we looked at how to do simple do-it-yourself authentication.


Links



')

Source: https://habr.com/ru/post/354862/


All Articles