LINE Developers: https://developers.line.biz/ja
・ Type de canal: Connexion en ligne ・ Types d'applications: application Web -URL de rappel: http : // localhost: 8080 / redirect (URL de destination de redirection après authentification)
2-1. Ajout de bibliothèques dépendantes
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
</dependency>
Sur la base du contenu suivant, passez l'utilisateur à l'écran d'authentification LINE et appelez l'API LINE pour acquérir des informations utilisateur
security.oauth2.client.clientId - Channnel ID security.oauth2.client.clientSecret - Channnel Secret security.oauth2.client.accessTokenUri --Endpoint à appeler lors de l'émission du jeton d'accès security.oauth2.client.userAuthorizationUri
application.yml
spring:
main:
allow-bean-definition-overriding: true
security:
oauth2:
client:
clientId: [CLIENT_ID]
clientSecret: [CLIENT_SECRET]
accessTokenUri: https://api.line.me/oauth2/v2.1/token
userAuthorizationUri: https://access.line.me/oauth2/v2.1/authorize
use-current-uri: false
pre-established-redirect-uri: https://localhost:8443/redirect
authorized-grant-types:
- authorization_code
- refresh_token
clientAuthenticationScheme: form
scope:
- openid
- email
- profile
resource:
userInfoUri: https://api.line.me/oauth2/v2.1/userinfo
preferTokenInfo: true
server:
port: 8443
ssl:
key-store: [.chemin du fichier p12]
key-store-password: [mot de passe]
keyStoreType: PKCS12
keyAlias: MyAlias
logging:
level:
org.springframework.web: DEBUG
ConfigComponent.java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
@Component
@PropertySource("classpath:application.yml")
@ConfigurationProperties(prefix = "security.oauth2.client")
public class ConfigComponent {
private String accessTokenUri;
private String clientId;
private String clientSecret;
@Value("${security.oauth2.client.pre-established-redirect-uri}")
private String redirecturi;
@Value("${security.oauth2.resource.userInfoUri}")
private String userInfoUri;
public String getAccessTokenUri() {
return this.accessTokenUri;
}
public void setAccessTokenUri(String accessTokenUri) {
this.accessTokenUri = accessTokenUri;
}
public String getClientId() {
return this.clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getRedirecturi() {
return this.redirecturi;
}
public void setRedirecturi(String redirecturi) {
this.redirecturi = redirecturi;
}
public String getClientSecret() {
return this.clientSecret;
}
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
public String getUserInfoUri() {
return this.userInfoUri;
}
public void setUserInfoUri(String userInfoUri) {
this.userInfoUri = userInfoUri;
}
}
--Enregistrez la classe d'acquisition d'informations variables définie ci-dessus dans le bean
ConfigBean.java
package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanConfig {
@Bean
public ConfigComponent configComponent() {
return new ConfigComponent();
}
@Bean
public LoginRestClient loginRestClient() {
return new LoginRestClient();
}
}
SecurityConfig.java
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
@EnableWebSecurity
@EnableOAuth2Sso
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(
"/images/**",
"/css/**",
"/javascript/**",
"/webjars/**",
"/favicon.ico");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/redirect/**")
.permitAll()
.and()
.authorizeRequests()
.antMatchers("/login/**")
.authenticated();
}
}
--Une fois l'authentification terminée, obtenez le code d'autorisation et exécutez la demande d'émission de jeton d'accès / d'acquisition d'informations utilisateur. -Injecter la classe LoginRestClient avec @Autowired --Passez l'objet obtenu au modèle Thymeleaf avec la classe ModelAndView
LoginController.java
import static java.util.Objects.requireNonNull;
import java.io.IOException;
import java.util.stream.IntStream;
import com.example.demo.LoginRestClient;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class LoginController {
@Autowired
LoginRestClient loginRestClient;
@RequestMapping(value = "/redirect", method = RequestMethod.GET)
public String getToken(@RequestParam("code") String code,
HttpServletRequest req, HttpServletResponse res) throws IOException{
LineToken responseToken = loginRestClient.getToken(code);
String accessTK = responseToken.getAccessTK();
String refreshTK = responseToken.getRefreshTK();
String idTK = responseToken.getIdTK();
Cookie accessTKCookie = new Cookie("access_token", accessTK);
accessTKCookie.setSecure(true);
Cookie refreshTKCookie = new Cookie("refresh_token", refreshTK);
refreshTKCookie.setSecure(true);
Cookie idTKCookie = new Cookie("id_token", idTK);
idTKCookie.setSecure(true);
res.addCookie(accessTKCookie);
res.addCookie(refreshTKCookie);
res.addCookie(idTKCookie);
return "redirect:/";
}
@RequestMapping(value = "/userinfo", method = RequestMethod.GET)
public ModelAndView getSubInfo(ModelAndView mv, HttpServletRequest req) throws IOException {
Cookie cookies[] = req.getCookies();
for(Cookie c: cookies) {
if(c.getName().equals("access_token")) {
System.err.println(c.getValue());
JSONObject userInfo =
new JSONObject(loginRestClient.getUserInfo(c.getValue()).getBody());
String sub = userInfo.getString("sub");
String name = userInfo.getString("name");
String picture = userInfo.getString("picture");
mv.addObject("sub", sub);
mv.addObject("name", name);
mv.addObject("picture", picture);
mv.setViewName("userinfo");
}
}
return mv;
}
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView getTopPage(ModelAndView mv, HttpServletRequest req) {
Cookie cookies[] = req.getCookies();
for(Cookie c: cookies) {
if(c.getName().equals("access_token")) {
mv.addObject("access_token", c.getValue());
} else if (c.getName().equals("refresh_token")) {
mv.addObject("refresh_token", c.getValue());
} else if (c.getName().equals("id_token")) {
mv.addObject("id_token", c.getValue());
}
}
mv.setViewName("index");
return mv;
}
}
LoginRestClient.java
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
@Component
public class LoginRestClient {
final static RestTemplate rs = new RestTemplate();
@Autowired
private ConfigComponent cc;
public LineToken getToken(String code) throws IOException {
code = Objects.requireNonNull(code);
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(cc.getClientId(), cc.getClientSecret());
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
params.add("code", code);
params.add("redirect_uri", cc.getRedirecturi());
params.add("grant_type", "authorization_code");
HttpEntity<MultiValueMap<String, Object>> requestEntity
= new HttpEntity<>(params, headers);
LineToken response = rs
.postForObject(cc.getAccessTokenUri(), requestEntity, LineToken.class);
return response;
}
public ResponseEntity<String> getUserInfo(String accessToken) throws IOException {
accessToken = Objects.requireNonNull(accessToken);
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(accessToken);
HttpEntity<MultiValueMap<String, Object>> requestEntity
= new HttpEntity<>(headers);
ResponseEntity<String> response =
rs.exchange(cc.getUserInfoUri(), HttpMethod.GET, requestEntity, String.class);
System.err.println(response);
return response;
}
}
LineToken.java
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import static java.util.Objects.requireNonNull;
public final class LineToken {
public final String accessToken;
public final String idToken;
public final String refreshToken;
@JsonCreator
LineToken(
@JsonProperty("access_token") String accessToken,
@JsonProperty("id_token") String idToken,
@JsonProperty("refresh_token") String refreshToken
) {
this.accessToken = requireNonNull(accessToken, "accessToken");
this.idToken = requireNonNull(idToken, "idToken");
this.refreshToken = requireNonNull(refreshToken, "refreshToken");
}
public String getAccessTK() {return this.accessToken;}
public String getIdTK() {return this.idToken;}
public String getrefreshTK() {return this.refreshToken;}
}
Étant donné que le jeton d'identification est retourné au format JWT, Base64 décode la partie en-tête / charge utile et fait référence au contenu.
entête: {"typ":"JWT","alg":"HS256"}
charge utile: {"iss":"https://access.line.me","sub":"**********","aud":"1653797412","exp":1579957272,"iat":1579953672,"amr":["linesso"],"name":"Yu","picture":"https://profile.line-scdn.net/0ho4KGrFFFMBt2PhvCq9pPTEp7PnYBEDZTDg98LVpsanhTXn4aTFx5Lwdpbn9SWnEYHwgtfFs3Znhd"}
Nom de la revendication | Réclamer le contenu |
---|---|
iss | Émetteur de jetons(ISSuer) |
sub | Cible des jetons(SUBubect) |
aud | Destinataire du jeton(AUDience) |
exp | Date d'expiration du jeton(EXPiration time) |
iat | Horodatage d'émission du jeton(Issued-AT) |