Auth0によるSpringセキュリティ
1. 概要
Auth0 は、ネイティブ、シングルページアプリケーション、Webなどのさまざまなタイプのアプリケーションに認証および承認サービスを提供します。 さらに、シングルサインオン、ソーシャルログイン、多要素認証などのさまざまな機能を実装できます。
このチュートリアルでは、Auth0アカウントの主要な構成とともに、ステップバイステップガイドを通じてSpringAuth0を使用したセキュリティについて説明します。
2. Auth0の設定
2.1. Auth0サインアップ
まず、
2.2. ダッシュボード
Auth0アカウントにログインすると、ログインアクティビティ、最新のログイン、新規サインアップなどの詳細を強調表示するダッシュボードが表示されます。
2.3. 新しいアプリケーションを作成する
次に、[アプリケーション]メニューから、Spring Boot用の新しいOpenID Connect(OIDC)アプリケーションを作成します。
さらに、 Native 、 Single-Page Apps 、 Machine to Machine Appsなどの利用可能なオプションから、アプリケーションタイプとして通常のWebアプリケーションを選択します :
2.4. アプリケーションの設定
次に、アプリケーションを指すコールバックURLやログアウトURLなどのいくつかのアプリケーションURIを構成します。
2.5. クライアントの資格情報
最後に、アプリに関連付けられているドメイン、クライアントID、、クライアントシークレットの値を取得します。
これらのクレデンシャルは、Spring Boot AppのAuth0セットアップに必要なため、手元に置いておいてください。
3. Spring Boot App Setup
Auth0アカウントでキー構成の準備ができたので、Auth0セキュリティをSpring Bootアプリに統合する準備が整いました。
3.1. Maven
まず、最新の mvc-auth-commonsMaven依存関係をpom.xmlに追加しましょう。
<dependency>
<groupId>com.auth0</groupId>
<artifactId>mvc-auth-commons</artifactId>
<version>1.2.0</version>
</dependency>
3.2. Gradle
同様に、Gradleを使用する場合、mvc-auth-commons依存関係をbuild.gradleファイルに追加できます。
compile 'com.auth0:mvc-auth-commons:1.2.0'
3.3. application.properties
Spring Bootアプリでは、Auth0アカウントの認証を有効にするために、クライアントIDやクライアントシークレットなどの情報が必要です。 そこで、それらをapplication.propertiesファイルに追加します。
com.auth0.domain: dev-example.auth0.com
com.auth0.clientId: {clientId}
com.auth0.clientSecret: {clientSecret}
3.4. AuthConfig
次に、 AuthConfig クラスを作成して、application.propertiesファイルからAuth0プロパティを読み取ります。
@Configuration
@EnableWebSecurity
public class AuthConfig extends WebSecurityConfigurerAdapter {
@Value(value = "${com.auth0.domain}")
private String domain;
@Value(value = "${com.auth0.clientId}")
private String clientId;
@Value(value = "${com.auth0.clientSecret}")
private String clientSecret;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http
.authorizeRequests()
.antMatchers("/callback", "/login", "/").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.and()
.logout().logoutSuccessHandler(logoutSuccessHandler()).permitAll();
}
}
さらに、 AuthConfig クラスは、WebSecurityConfigurerAdapterクラス。を拡張することによってWebセキュリティを有効にするように構成されています。
3.5. AuthenticationController
最後に、AuthenticationControllerクラスのbean参照をすでに説明したAuthConfigクラスに追加します。
@Bean
public AuthenticationController authenticationController() throws UnsupportedEncodingException {
JwkProvider jwkProvider = new JwkProviderBuilder(domain).build();
return AuthenticationController.newBuilder(domain, clientId, clientSecret)
.withJwkProvider(jwkProvider)
.build();
}
ここでは、 AuthenticationController クラスのインスタンスを構築する際に、JwkProviderBuilderクラスを使用しました。 これを使用して公開鍵をフェッチし、トークンの署名を検証します(デフォルトでは、トークンはRS256非対称署名アルゴリズムを使用して署名されます)。
さらに、 authenticationController Beanは、ログイン用の認証URLを提供し、コールバック要求を処理します。
4. AuthController
次に、ログインおよびコールバック機能用のAuthControllerクラスを作成します。
@Controller
public class AuthController {
@Autowired
private AuthConfig config;
@Autowired
private AuthenticationController authenticationController;
}
ここでは、前のセクションで説明したAuthConfigクラスとAuthenticationControllerクラスの依存関係を挿入しました。
4.1. ログイン
login メソッドを作成して、Spring Bootアプリがユーザーを認証できるようにします。
@GetMapping(value = "/login")
protected void login(HttpServletRequest request, HttpServletResponse response) {
String redirectUri = "http://localhost:8080/callback";
String authorizeUrl = authenticationController.buildAuthorizeUrl(request, response, redirectUri)
.withScope("openid email")
.build();
response.sendRedirect(authorizeUrl);
}
buildAuthorizeUrl メソッドは、Auth0承認URLを生成し、デフォルトのAuth0サインイン画面にリダイレクトします。
4.2. 折り返し電話
ユーザーがAuth0クレデンシャルでサインインすると、コールバックリクエストがSpringBootAppに送信されます。 そのために、コールバックメソッドを作成しましょう。
@GetMapping(value="/callback")
public void callback(HttpServletRequest request, HttpServletResponse response) {
Tokens tokens = authenticationController.handle(request, response);
DecodedJWT jwt = JWT.decode(tokens.getIdToken());
TestingAuthenticationToken authToken2 = new TestingAuthenticationToken(jwt.getSubject(),
jwt.getToken());
authToken2.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(authToken2);
response.sendRedirect(config.getContextPath(request) + "/");
}
コールバックリクエストを処理して、認証の成功を表すaccessTokenとidTokenを取得しました。 次に、 TestingAuthenticationToken オブジェクトを作成して、SecurityContextHolderで認証を設定しました。
ただし、使いやすさを向上させるために、AbstractAuthenticationTokenクラスの実装を作成できます。
5. HomeController
最後に、アプリケーションのランディングページのデフォルトのマッピングを使用してHomeControllerを作成します。
@Controller
public class HomeController {
@GetMapping(value = "/")
@ResponseBody
public String home(final Authentication authentication) {
TestingAuthenticationToken token = (TestingAuthenticationToken) authentication;
DecodedJWT jwt = JWT.decode(token.getCredentials().toString());
String email = jwt.getClaims().get("email").asString();
return "Welcome, " + email + "!";
}
}
ここでは、idTokenからDecodedJWTオブジェクトを抽出しました。 さらに、電子メールなどのユーザー情報はクレームから取得されます。
それでおしまい! Spring Boot Appは、Auth0セキュリティサポートを備えています。 Mavenコマンドを使用してアプリを実行してみましょう。
mvn spring-boot:run
localhost:8080 / login、でアプリケーションにアクセスすると、Auth0によって提供されるデフォルトのサインインページが表示されます。
登録ユーザーの資格情報を使用してログインすると、ユーザーの電子メールを含むウェルカムメッセージが表示されます。
また、自己登録用のデフォルトのサインイン画面に「サインアップ」ボタン(「ログイン」の横)があります。
6. サインアップ
6.1. 自己登録
初めて、「サインアップ」ボタンを使用してAuth0アカウントを作成し、電子メールやパスワードなどの情報を提供できるようになりました。
6.2. ユーザーを作成する
または、Auth0アカウントのUsersメニューから新しいユーザーを作成できます。
6.3. 接続設定
さらに、Spring Bootアプリへのサインアップ/サインインのために、データベースやソーシャルログインなどのさまざまなタイプの接続を選択できます。
さらに、さまざまなソーシャルコネクションを選択できます。
7. LogoutController
ログイン機能とコールバック機能を確認したので、ログアウト機能をSpring Bootアプリに追加できます。
LogoutSuccessHandlerクラスを実装するLogoutControllerクラスを作成しましょう。
@Controller
public class LogoutController implements LogoutSuccessHandler {
@Autowired
private AuthConfig config;
@Override
public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse res,
Authentication authentication) {
if (req.getSession() != null) {
req.getSession().invalidate();
}
String returnTo = "http://localhost:8080/";
String logoutUrl = "https://dev-example.auth0.com/v2/logout?client_id=" +
config.getClientId() + "&returnTo=" +returnTo;
res.sendRedirect(logoutUrl);
}
}
ここで、 onLogoutSuccess メソッドは、 / v2 / logoutAuth0ログアウトURLを呼び出すためにオーバーライドされます。
8. Auth0管理API
これまで、Spring BootアプリでのAuth0セキュリティの統合を見てきました。 それでは、同じアプリでAuth0 Management API(システムAPI)を操作してみましょう。
8.1. 新しいアプリケーションを作成する
まず、Auth0 Management APIにアクセスするために、Auth0アカウントに Machine to MachineApplicationを作成します。
8.2. 承認
次に、ユーザーの読み取り/作成の権限を持つAuth0ManagementAPIに承認を追加します。
8.3. クライアントの資格情報
最後に、クライアントIDとクライアントシークレットを受け取り、Spring BootアプリからAuth0管理アプリにアクセスします。
8.4. アクセストークン
前のセクションで受け取ったクライアント資格情報を使用して、Auth0管理アプリのアクセストークンを生成しましょう。
public String getManagementApiToken() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
JSONObject requestBody = new JSONObject();
requestBody.put("client_id", "auth0ManagementAppClientId");
requestBody.put("client_secret", "auth0ManagementAppClientSecret");
requestBody.put("audience", "https://dev-example.auth0.com/api/v2/");
requestBody.put("grant_type", "client_credentials");
HttpEntity<String> request = new HttpEntity<String>(requestBody.toString(), headers);
RestTemplate restTemplate = new RestTemplate();
HashMap<String, String> result = restTemplate
.postForObject("https://dev-example.auth0.com/oauth/token", request, HashMap.class);
return result.get("access_token");
}
ここでは、 / oauth / token Auth0トークンURLにRESTリクエストを送信して、アクセストークンと更新トークンを取得しました。
また、これらのクライアント資格情報を application.properties ファイルに保存し、AuthConfigクラスを使用して読み取ることができます。
8.5. UserController
その後、usersメソッドを使用してUserControllerクラスを作成しましょう。
@Controller
public class UserController {
@GetMapping(value="/users")
@ResponseBody
public ResponseEntity<String> users(HttpServletRequest request, HttpServletResponse response) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + getManagementApiToken());
HttpEntity<String> entity = new HttpEntity<String>(headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> result = restTemplate
.exchange("https://dev-example.auth0.com/api/v2/users", HttpMethod.GET, entity, String.class);
return result;
}
}
users メソッドは、前のセクションで生成されたアクセストークンを使用して / api / v2 / users Auth0 APIにGETリクエストを行うことにより、すべてのユーザーのリストをフェッチします。
それでは、 localhost:8080 / users にアクセスして、すべてのユーザーを含むJSON応答を受信しましょう。
[{
"created_at": "2020-05-05T14:38:18.955Z",
"email": "[email protected]",
"email_verified": true,
"identities": [
{
"user_id": "5eb17a5a1cc1ac0c1487c37f78758",
"provider": "auth0",
"connection": "Username-Password-Authentication",
"isSocial": false
}
],
"name": "[email protected]",
"nickname": "ansh",
"logins_count": 64
// ...
}]
8.6. ユーザーを作成
同様に、 / api / v2 / users Auth0 APIに対してPOSTリクエストを行うことで、ユーザーを作成できます。
@GetMapping(value = "/createUser")
@ResponseBody
public ResponseEntity<String> createUser(HttpServletResponse response) {
JSONObject request = new JSONObject();
request.put("email", "[email protected]");
request.put("given_name", "Norman");
request.put("family_name", "Lewis");
request.put("connection", "Username-Password-Authentication");
request.put("password", "Pa33w0rd");
// ...
ResponseEntity<String> result = restTemplate
.postForEntity("https://dev-example.auth0.com/api/v2/users", request.toString(), String.class);
return result;
}
次に、 localhost:8080 / createUser にアクセスして、新しいユーザーの詳細を確認しましょう。
{
"created_at": "2020-05-10T12:30:15.343Z",
"email": "[email protected]",
"email_verified": false,
"family_name": "Lewis",
"given_name": "Norman",
"identities": [
{
"connection": "Username-Password-Authentication",
"user_id": "5eb7f3d76b69bc0c120a8901576",
"provider": "auth0",
"isSocial": false
}
],
"name": "[email protected]",
"nickname": "norman.lewis",
// ...
}
同様に、権限に応じて、Auth0 APIを使用して、すべての接続の一覧表示、接続の作成、すべてのクライアントの一覧表示、クライアントの作成などのさまざまな操作を実行できます。
9. 結論
このチュートリアルでは、Auth0を使用したSpringSecurityについて説明しました。
まず、基本的な構成でAuth0アカウントを設定します。 次に、Spring Boot Appを作成し、application.propertiesをAuth0とのSpringSecurity統合用に構成しました。
次に、Auth0管理APIのAPIトークンの作成を検討しました。 最後に、すべてのユーザーの取得やユーザーの作成などの機能について検討しました。
いつものように、すべてのコード実装はGitHubで利用できます。