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
- Changgou Mall (1): Environment Construction
- Changgou Mall (2): Distributed File System FastDFS
- Changgou Mall (3): Commodity Management
- Changgou Mall (4): Lua, OpenResty, Canal realize advertising caching and synchronization
- Changgou Mall (5): Elasticsearch realizes product search
- Changgou Mall (6): Product Search
- Changgou Mall (7): Thymeleaf realizes static pages
- Changgou Mall (8): Microservice Gateway and JWT Token
- Changbu Mall (9): Spring Security Oauth2
- Changgou Mall (10): Shopping Cart
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.
-
LoginService
withLoginServiceImpl
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!