Changbu Mall (9): Spring Security Oauth2

study hard, improve every day

This article has been included in my Github warehouse DayDayUP : github.com/RobodLee/DayDayUP, welcome to Star, for more articles, please go to: Directory Navigation

Preface

I didn't learn Spring Security and OAuth2.0 before, so I was confused when watching the video in this chapter. So it took a few days to make up for this knowledge, and wrote two articles to explain these two parts in detail.

The following content is only for this project, the content mentioned in the previous two articles will not be said again.

Certification service introduction

How to build OAuth2.0 I have already explained in detail in the previous article, here you can directly import the code provided in the information.

Here is a brief summary of the role of each file:

  • AuthorizationServerConfig

    This is the authentication service configuration of OAuth2.0. There are three main points. The first is the configuration of client information , that is, what conditions the client needs to access the server, such as client id and client key, etc., which can be directly configured in memory or read from the database Take; The second is the authorization server endpoint configuration , which is to configure the authentication manager, token storage method, etc.; the third is the security configuration of the authorization server , which is to configure access restrictions, such as restricting the configuration of verification tokens.

  • CustomUserAuthenticationConverter

    The custom UserAuthenticationConverter inherits from DefaultUserAuthenticationConverter and overrides the convertUserAuthentication method. The default method is to obtain the username and permission information in authentication . In the rewritten method, we also get the principal in the authentication to determine whether it is our custom UserJwt . If not, call userDetailsService.loadUserByUsername to get it, and then get the name and id in userJwt and add them to the returned map. in.

  • UserDetailsServiceImpl

    This is a custom authentication and authorization class that implements the UserDetailsService interface and implements the loadUserByUsername() method inside. This method is to find out the corresponding user information based on the user name passed in from the front end. Then hand it over to subsequent filters to verify user identity. Generally, this method is to find users from the database, but for testing purposes, a temporary user is directly new, the password is "robod666", so as long as the password passed from the front end is "robod666", you can log in normally.

  • WebSecurityConfig

    This is the security configuration class of Spring Security. It is mainly configured with certain restrictions on certain requests. In this class, passwordEncoder and authenticationManagerBean are also injected into the Spring container for other classes to use.

  • UserLoginController

    This is a self-defined simplified login method that only uses username and password to log in.

  • LoginServicewithLoginServiceImpl

    Service layer of UserLoginController. Responsible for adding some necessary information and then sending a request to the server to obtain the token information through the RestTemplate simulation browser.

  • AuthToken

    Encapsulates Token related information. Token information, refresh token, jwt short token.

  • CookieUtil

    Cookie tools. Set cookies and get cookie information based on name.

  • UserJwt

    User Info. Implemented UserDetails interface. This class of objects is used when authenticating users.

  • changgou.jks

    The key certificate can be generated using the keytool tool.

  • application.yml

    Authentication service configuration file

    …………
    # 配置信息,给UserLoginController用的
    auth:
      ttl: 3600  #token存储到redis的过期时间
      clientId: changgou
      clientSecret: changgou
      cookieDomain: localhost
      cookieMaxAge: -1
    
    # 因为采用了非对称加密,所以这里配置了密钥的相关信息
    encrypt:
      key-store:
        location: classpath:/robod666.jks
        secret: robod666
        alias: robod666
        password: robod666
        …………
    

The role of these files is introduced here.

Asymmetric encryption authentication

Certification process analysis

This is the traditional authentication process. When we carry the token to access the resource server, the resource service will send the token to the authorization service to verify that the token is valid. Doing so will increase the server pressure invisibly, because there is one more interaction between the servers, which is inefficient.

In order to improve efficiency, a public key private key verification method is adopted.

The authorization service uses the private key to generate the token, and then the client carries the token and sends a request to the resource server. The resource server uses the public key to verify the token, and then proceed to the next step after the verification is passed. Reduce the interaction with the authorization service.

The public key can be stored in any server, but the private key can only be stored in the authorization service. Because after having the private key, the token can be forged, which reduces the security. Therefore, asymmetric encryption is also used to improve security.

Generate key certificate

We can use the keytool tool to generate a key pair. In the prepared folder, open a command line window and execute the following:

keytool -genkeypair -alias robod666 -keyalg RSA -keypass robod666 -keystore robod666.jks -storepass robod666
# -alias:密钥的别名 
# -keyalg:使用的hash算法 
# -keypass:密钥的访问密码
# -keystore:密钥库文件名,xc.keystore保存了生成的证书 
# -storepass:密钥库的访问密码 

Then there will be several questions on the interface, just enter the answer, and finally enter " y " to generate the key.

Put the generated key certificate in the resources directory of the authentication service .

Extract public key

After installing openssl , open a command line window in the directory where the key certificate is located, and execute

keytool -list -rfc --keystore robod666.jks | openssl x509 -inform pem -pubkey

In this way, the public key can be extracted. Create a public.key file in the resources directory of the microservice that needs to use the public key, and merge this content into one line and paste it in.

Create and parse token

public class JWTTest {
    
    

    //创建令牌
    @Test
    public void createJWT() {
    
    
        ClassPathResource classPathResource = new ClassPathResource("robod666.jks");
        KeyStoreKeyFactory keyStoreKeyFactory = 
            new KeyStoreKeyFactory(classPathResource, "robod666".toCharArray());
        KeyPair keyPair = keyStoreKeyFactory.getKeyPair("robod666");
        PrivateKey privateKey = keyPair.getPrivate();
        Map<String, Object> tokenMap = new HashMap<>();
        tokenMap.put("id", "1");
        tokenMap.put("name", "robod");
        tokenMap.put("roles", "ROLE_VIP,ROLE_USER");
        Jwt jwt = JwtHelper.encode(JSON.toJSONString(tokenMap), new RsaSigner((RSAPrivateKey) privateKey));
        System.out.println(jwt.getEncoded());
    }

    //解析令牌
    @Test
    public void parseJWT() {
    
    
        String token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlcyI6IlJPTEVfVklQLFJPTEVfVVNFUiIsIm5hbWUiOiJyb2JvZCIsImlkIjoiMSJ9.KkPXXlYTkDCWq2VN5qy6w6FI5TgCbIy-GkQShaYGbfvcZsj0165XsgXSx7Sf5aUpGB-494ds-ZnLxs3oVMZ7_tbu-is1-gZOeQ0G1GLla0ytNkImXabnujgWH2B4bmX4lBLK7d8xTEQ4WoAnydWUusCmPjQDgdFZGHmccJLuYKqQPzru-4go1mFgjEeB7gNu6cLYyQc79bZdF2Mk2OX1Nxpb88sux0QkNAlb1-JuUhmjbUYwMK5l5W5zeNckRJtGy_Zy7OTwXviuRp6uISmWD7p1HYbkKH-ROKCgSu1cqnok0645Uou7Y54Nd8NosIqShuNYbBBo_BHWuyx_lKdk1g";
        String publicKey = "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiq6KfbXc/viuB6oQ/80cfLSFIr7pX3PmteAQ2/dA+ReMLgULJb+U8Dax3xNpBgLAp+Ei2IMkBFJlJRn/iaYi5eMnCY2vyfHkC69x6OhhCtzWBRxGJkPRjLDU+Obhak2MrDI4zIpzQs2/phjqWXuEPMz7KMd5UhoAFZWLTW1Ih3CP962fuJdV83hj/2uWN/yaAgaLRxRlTw7HHoIEy1dX9prAnqQ/rOl2Igvwi23GNnzMrqlvR9qt1gBI+noHtMv07hkavUT1nmoYnt/pw2+FLMLFEun2gR3DUmqu79QC6trDf3cVfKyRP9A7TBjUEv+Ecrh8JQosQa8GongTzHhmOwIDAQAB-----END PUBLIC KEY-----";
        Jwt jwt = JwtHelper.decodeAndVerify(token, new RsaVerifier(publicKey));
        String claims = jwt.getClaims();
        System.out.println(claims);
    }
}

When creating a token, the following java.lang.IllegalStateException error may occur ,

Just restart the idea.

If you run createJWT() successfully, the following content will appear.

This is the token we created.

Run parseJWT(), if the operation is successful, you can use the public key to parse the content of the token.

Account password login

Now when we log in, in addition to the username and password, we also need to specify other information such as clientId. Can we log in using only the account password? Just specify other information in the server in advance. The idea is that the front end will pass in the username and password, and then the server will add other information, send it to the authentication service to log in, and then get the token and return it to the front end.

@Service
public class LoginServiceImpl implements LoginService {
    
    

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @Override
    public Map login(String username, String password, String clientId, String clientSecret, String grantType) {
    
    
        String url = loadBalancerClient.choose("user-auth").getUri() +
                "/oauth/token";
        //请求体
        MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
        body.add("username", username);
        body.add("password", password);
        body.add("grant_type", grantType);
        //请求头
        MultiValueMap<String, String> header = new LinkedMultiValueMap<>();
        String authorization = "Basic " +
                new String(Base64.getEncoder().encode((clientId + ":" + clientSecret).getBytes()));
        header.add("Authorization", authorization);
        HttpEntity httpEntity = new HttpEntity(body, header);
        ResponseEntity<Map> response = restTemplate.exchange(url, HttpMethod.POST, httpEntity, Map.class);
        return response.getBody();
    }

}
@Value("${auth.clientId}")
private String clientId;

@Value("${auth.clientSecret}")
private String clientSecret;

//密码模式  认证.
@RequestMapping("/login")
public Result<Map> login(String username, String password) throws Exception {
    
    
    String grantType = "password";
    Map token = loginService.login(username, password, clientId, clientSecret, grantType);
    return new Result<>(true, StatusCode.OK,"令牌生成成功",token);
}

Ok, now we can apply for the token with only the account password.

to sum up

This article mainly talks about how to import OAuth2.0 authentication service. If you don’t understand it, it’s still very difficult to understand, so you can go to my previous article first. After importing, I have a simple description of the role of each file. Introduction. Then I talked about how to generate public and private keys when using asymmetric encryption. Finally, I talked about how to log in with only the account and password.

If my article for you some help, do not forget to thumbs up , collection , forwarding , attention . If you have any good comments, please leave a message below. Let's see you next time!

WeChat public account

Guess you like

Origin blog.csdn.net/weixin_43461520/article/details/108144023