Я работаю над тем, как использовать платформу Play. Я понимаю, что плагины могут использоваться для добавления функциональных возможностей, которые другие разработали. Может быть, я должен назвать его модулем? Я прочитал, что SercureSocial является одним из лучших модулей, доступных для аутентификации. Но документация на самом деле меня не доставила. Может ли кто-нибудь помочь мне понять, как добавить мастер-снимок в мой существующий проект java?
Предположим, что я выполнил активатор new my-first-app play-scala activator eclipse. Я импортировал в eclipse проект
Следующий шаг - попытаться следовать указаниям из следующего URL-адреса
http://securesocial.ws/guide/installation.html
После прочтения я все еще потерян.
Нет файла Build.scala, но я вижу, что есть файл build.sbt. Добавить этот блок в файл build.sbt?
object ApplicationBuild extends Build {
val appName = "my-first-app"
val appVersion = "1.0-SNAPSHOT"
val appDependencies = Seq(
"ws.securesocial" %% "securesocial" % "master-SNAPSHOT"
)
val main = play.Project(appName, appVersion, appDependencies).settings(
resolvers += Resolver.sonatypeRepo("releases")
)
val main = play.Project(appName, appVersion, appDependencies).settings(
resolvers += Resolver.sonatypeRepo("snapshots")
)
После копирования блока выше, я создал файл ply.plugins в папке conf. Затем я скопировал все плагины в файл и сохранил
1500:com.typesafe.plugin.CommonsMailerPlugin
9994:securesocial.core.DefaultAuthenticatorStore
9995:securesocial.core.DefaultIdGenerator
9996:securesocial.core.providers.utils.DefaultPasswordValidator
9997:securesocial.controllers.DefaultTemplatesPlugin
9998:your.user.Service.Implementation <-- Important: You need to change this
9999:securesocial.core.providers.utils.BCryptPasswordHasher
10000:securesocial.core.providers.TwitterProvider
10001:securesocial.core.providers.FacebookProvider
10002:securesocial.core.providers.GoogleProvider
10003:securesocial.core.providers.LinkedInProvider
10004:securesocial.core.providers.UsernamePasswordProvider
10005:securesocial.core.providers.GitHubProvider
10006:securesocial.core.providers.FoursquareProvider
10007:securesocial.core.providers.XingProvider
10008:securesocial.core.providers.VkProvider
10009:securesocial.core.providers.InstagramProvider
Затем я копирую все маршруты в файл маршрутов
# Login page
GET /login securesocial.controllers.LoginPage.login
GET /logout securesocial.controllers.LoginPage.logout
# User Registration and password handling
GET /signup securesocial.controllers.Registration.startSignUp
POST /signup securesocial.controllers.Registration.handleStartSignUp
GET /signup/:token securesocial.controllers.Registration.signUp(token)
POST /signup/:token securesocial.controllers.Registration.handleSignUp(token)
GET /reset securesocial.controllers.Registration.startResetPassword
POST /reset securesocial.controllers.Registration.handleStartResetPassword
GET /reset/:token securesocial.controllers.Registration.resetPassword(token)
POST /reset/:token securesocial.controllers.Registration.handleResetPassword(token)
GET /password securesocial.controllers.PasswordChange.page
POST /password securesocial.controllers.PasswordChange.handlePasswordChange
# Providers entry points
GET /authenticate/:provider securesocial.controllers.ProviderController.authenticate(provider)
POST /authenticate/:provider securesocial.controllers.ProviderController.authenticateByPost(provider)
GET /not-authorized securesocial.controllers.ProviderController.notAuthorized
Затем я пытаюсь запустить проект, и я получаю следующую ошибку
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: UNRESOLVED DEPENDENCIES ::
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: ws.securesocial#securesocial;2.1.4: not found
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn]
[warn] Note: Some unresolved dependencies have extra attributes. Check that these dependencies exist with the requested attributes.
[warn] ws.securesocial:securesocial:2.1.4 (scalaVersion=2.10, sbtVersion=0.13)
[warn]
sbt.ResolveException: unresolved dependency: ws.securesocial#securesocial;2.1.4:not found
at sbt.IvyActions$.sbt$IvyActions$$resolve(IvyActions.scala:217)
at sbt.IvyActions$$anonfun$update$1.apply(IvyActions.scala:126)
at sbt.IvyActions$$anonfun$update$1.apply(IvyActions.scala:125)
at sbt.IvySbt$Module$$anonfun$withModule$1.apply(Ivy.scala:115)
at sbt.IvySbt$Module$$anonfun$withModule$1.apply(Ivy.scala:115)
at sbt.IvySbt$$anonfun$withIvy$1.apply(Ivy.scala:103)
at sbt.IvySbt.sbt$IvySbt$$action$1(Ivy.scala:48)
at sbt.IvySbt$$anon$3.call(Ivy.scala:57)
at xsbt.boot.Locks$GlobalLock.withChannel$1(Locks.scala:93)
at xsbt.boot.Locks$GlobalLock.xsbt$boot$Locks$GlobalLock$$withChannelRetries$1(Locks.scala:78)
at xsbt.boot.Locks$GlobalLock$$anonfun$withFileLock$1.apply(Locks.scala:97)
at xsbt.boot.Using$.withResource(Using.scala:10)
at xsbt.boot.Using$.apply(Using.scala:9)
at xsbt.boot.Locks$GlobalLock.ignoringDeadlockAvoided(Locks.scala:58)
at xsbt.boot.Locks$GlobalLock.withLock(Locks.scala:48)
at xsbt.boot.Locks$.apply0(Locks.scala:31)
at xsbt.boot.Locks$.apply(Locks.scala:28)
at sbt.IvySbt.withDefaultLogger(Ivy.scala:57)
at sbt.IvySbt.withIvy(Ivy.scala:98)
at sbt.IvySbt.withIvy(Ivy.scala:94)
at sbt.IvySbt$Module.withModule(Ivy.scala:115)
at sbt.IvyActions$.update(IvyActions.scala:125)
at sbt.Classpaths$$anonfun$sbt$Classpaths$$work$1$1.apply(Defaults.scala:1223)
at sbt.Classpaths$$anonfun$sbt$Classpaths$$work$1$1.apply(Defaults.scala:1221)
at sbt.Classpaths$$anonfun$doWork$1$1$$anonfun$74.apply(Defaults.scala:1244)
at sbt.Classpaths$$anonfun$doWork$1$1$$anonfun$74.apply(Defaults.scala:1242)
at sbt.Tracked$$anonfun$lastOutput$1.apply(Tracked.scala:35)
at sbt.Classpaths$$anonfun$doWork$1$1.apply(Defaults.scala:1246)
at sbt.Classpaths$$anonfun$doWork$1$1.apply(Defaults.scala:1241)
at sbt.Tracked$$anonfun$inputChanged$1.apply(Tracked.scala:45)
at sbt.Classpaths$.cachedUpdate(Defaults.scala:1249)
at sbt.Classpaths$$anonfun$updateTask$1.apply(Defaults.scala:1214)
at sbt.Classpaths$$anonfun$updateTask$1.apply(Defaults.scala:1192)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:42)
at sbt.std.Transform$$anon$4.work(System.scala:64)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:18)
at sbt.Execute.work(Execute.scala:244)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:160)
at sbt.CompletionService$$anon$2.call(CompletionService.scala:30)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
[error] (*:update) sbt.ResolveException: unresolved dependency: ws.securesocial#securesocial;2.1.4: not found
Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore?
Может ли кто-нибудь помочь мне понять, как добавить мастер-снимок в мой существующий проект java?
Я только пробовал с версией Scala, а не с Java, но я надеюсь, что следующее поможет немного.
В файле build.sbt добавьте следующую строку в библиотеку:
"ws.securesocial" %% "securesocial" % "master-SNAPSHOT"
Нет файла Build.scala, но я вижу, что есть файл build.sbt. Добавить этот блок в файл build.sbt?
Единственное, что вам нужно добавить в build.sbt, это URL-адрес репозитория Snapshots сонатного типа OSS:
resolvers +=
"Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"
После копирования блока выше, я создал файл ply.plugins в папке conf. Затем я скопировал все плагины в файл и сохранил
Единственный плагин, который вам нужно настроить в файле play.plugins, - это CommonsMailerPlugin:
1500:com.typesafe.plugin.CommonsMailerPlugin
Затем я копирую все маршруты в файл маршрутов
Попробуйте приведенное ниже в качестве примера вместо того, что было у вас на основе старой версии securesocal:
# your secure page
GET / @controllers.Application.index
# securesocial routes
GET /login @securesocial.controllers.LoginPage.login
GET /logout @securesocial.controllers.LoginPage.logout
-> /auth securesocial.Routes
Чтобы запустить рабочий пример, вам понадобится следующее:
securesocial.conf https://github.com/jaliss/securesocial/blob/master/samples/scala/demo/conf/securesocial.conf
Вам нужно будет настроить ваши настройки почты smtp и любую конфигурацию securesocial.
InMemoryUserService
/**
* Copyright 2012 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package service
import play.api.Logger
import securesocial.core._
import securesocial.core.providers.{ UsernamePasswordProvider, MailToken }
import scala.concurrent.Future
import securesocial.core.services.{ UserService, SaveMode }
/**
* A Sample In Memory user service in Scala
*
* IMPORTANT: This is just a sample and not suitable for a production environment since
* it stores everything in memory.
*/
class InMemoryUserService extends UserService[DemoUser] {
val logger = Logger("application.controllers.InMemoryUserService")
//
var users = Map[(String, String), DemoUser]()
//private var identities = Map[String, BasicProfile]()
private var tokens = Map[String, MailToken]()
def find(providerId: String, userId: String): Future[Option[BasicProfile]] = {
if (logger.isDebugEnabled) {
logger.debug("users = %s".format(users))
}
val result = for (
user <- users.values;
basicProfile <- user.identities.find(su => su.providerId == providerId && su.userId == userId)
) yield {
basicProfile
}
Future.successful(result.headOption)
}
def findByEmailAndProvider(email: String, providerId: String): Future[Option[BasicProfile]] = {
if (logger.isDebugEnabled) {
logger.debug("users = %s".format(users))
}
val someEmail = Some(email)
val result = for (
user <- users.values;
basicProfile <- user.identities.find(su => su.providerId == providerId && su.email == someEmail)
) yield {
basicProfile
}
Future.successful(result.headOption)
}
private def findProfile(p: BasicProfile) = {
users.find {
case (key, value) if value.identities.exists(su => su.providerId == p.providerId && su.userId == p.userId) => true
case _ => false
}
}
private def updateProfile(user: BasicProfile, entry: ((String, String), DemoUser)): Future[DemoUser] = {
val identities = entry._2.identities
val updatedList = identities.patch(identities.indexWhere(i => i.providerId == user.providerId && i.userId == user.userId), Seq(user), 1)
val updatedUser = entry._2.copy(identities = updatedList)
users = users + (entry._1 -> updatedUser)
Future.successful(updatedUser)
}
def save(user: BasicProfile, mode: SaveMode): Future[DemoUser] = {
mode match {
case SaveMode.SignUp =>
val newUser = DemoUser(user, List(user))
users = users + ((user.providerId, user.userId) -> newUser)
Future.successful(newUser)
case SaveMode.LoggedIn =>
// first see if there is a user with this BasicProfile already.
findProfile(user) match {
case Some(existingUser) =>
updateProfile(user, existingUser)
case None =>
val newUser = DemoUser(user, List(user))
users = users + ((user.providerId, user.userId) -> newUser)
Future.successful(newUser)
}
case SaveMode.PasswordChange =>
findProfile(user).map { entry => updateProfile(user, entry) }.getOrElse(
// this should not happen as the profile will be there
throw new Exception("missing profile)")
)
}
}
def link(current: DemoUser, to: BasicProfile): Future[DemoUser] = {
if (current.identities.exists(i => i.providerId == to.providerId && i.userId == to.userId)) {
Future.successful(current)
} else {
val added = to :: current.identities
val updatedUser = current.copy(identities = added)
users = users + ((current.main.providerId, current.main.userId) -> updatedUser)
Future.successful(updatedUser)
}
}
def saveToken(token: MailToken): Future[MailToken] = {
Future.successful {
tokens += (token.uuid -> token)
token
}
}
def findToken(token: String): Future[Option[MailToken]] = {
Future.successful { tokens.get(token) }
}
def deleteToken(uuid: String): Future[Option[MailToken]] = {
Future.successful {
tokens.get(uuid) match {
case Some(token) =>
tokens -= uuid
Some(token)
case None => None
}
}
}
// def deleteTokens(): Future {
// tokens = Map()
// }
def deleteExpiredTokens() {
tokens = tokens.filter(!_._2.isExpired)
}
override def updatePasswordInfo(user: DemoUser, info: PasswordInfo): Future[Option[BasicProfile]] = {
Future.successful {
for (
found <- users.values.find(_ == user);
identityWithPasswordInfo <- found.identities.find(_.providerId == UsernamePasswordProvider.UsernamePassword)
) yield {
val idx = found.identities.indexOf(identityWithPasswordInfo)
val updated = identityWithPasswordInfo.copy(passwordInfo = Some(info))
val updatedIdentities = found.identities.patch(idx, Seq(updated), 1)
val updatedEntry = found.copy(identities = updatedIdentities)
users = users + ((updatedEntry.main.providerId, updatedEntry.main.userId) -> updatedEntry)
updated
}
}
}
override def passwordInfoFor(user: DemoUser): Future[Option[PasswordInfo]] = {
Future.successful {
for (
found <- users.values.find(u => u.main.providerId == user.main.providerId && u.main.userId == user.main.userId);
identityWithPasswordInfo <- found.identities.find(_.providerId == UsernamePasswordProvider.UsernamePassword)
) yield {
identityWithPasswordInfo.passwordInfo.get
}
}
}
}
// a simple User class that can have multiple identities
case class DemoUser(main: BasicProfile, identities: List[BasicProfile])
Global.scala
Scala https://github.com/jaliss/securesocial/blob/master/samples/scala/demo/app/Global.scala
Java https://github.com/jaliss/securesocial/blob/master/samples/java/demo/app/Global.java
/**
* Copyright 2014 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import controllers.CustomRoutesService
import java.lang.reflect.Constructor
import securesocial.core.RuntimeEnvironment
import service.{ DemoUser, MyEventListener, InMemoryUserService }
object Global extends play.api.GlobalSettings {
/**
* The runtime environment for this sample app.
*/
object MyRuntimeEnvironment extends RuntimeEnvironment.Default[DemoUser] {
override implicit val executionContext = play.api.libs.concurrent.Execution.defaultContext
override lazy val routes = new CustomRoutesService()
override lazy val userService: InMemoryUserService = new InMemoryUserService()
override lazy val eventListeners = List(new MyEventListener())
}
/**
* An implementation that checks if the controller expects a RuntimeEnvironment and
* passes the instance to it if required.
*
* This can be replaced by any DI framework to inject it differently.
*
* @param controllerClass
* @tparam A
* @return
*/
override def getControllerInstance[A](controllerClass: Class[A]): A = {
val instance = controllerClass.getConstructors.find { c =>
val params = c.getParameterTypes
params.length == 1 && params(0) == classOf[RuntimeEnvironment[DemoUser]]
}.map {
_.asInstanceOf[Constructor[A]].newInstance(MyRuntimeEnvironment)
}
instance.getOrElse(super.getControllerInstance(controllerClass))
}
}
Защищенный прикладной контроллер
package controllers
import play.api._
import play.api.mvc._
import securesocial.core._
import service.DemoUser
class Application(override implicit val env: RuntimeEnvironment[DemoUser]) extends SecureSocial[DemoUser] {
def index = SecuredAction { implicit request =>
Ok(views.html.index(request.user.main))
}
}
Защищенная страница - index.scala.html
@(user: securesocial.core.BasicProfile)(implicit request: RequestHeader, env: securesocial.core.RuntimeEnvironment[service.DemoUser])
@main("Secure Page") {
<h2>User Id:@user.userId</h2>
<hr>
<a class="btn" href="@securesocial.controllers.routes.LoginPage.logout()">Logout</a>
}
Я пережил это сам последние пару дней. На данный момент я предлагаю вам игнорировать документацию. Это не актуально (документация на 2, но 3, кажется, необходима для игры 2.3.x). Такие вещи, как play.plugins, отправляют вас по неправильному пути.
Объединив установку для установки M3 на 2.3.X, было грубо, но я думаю, что я работаю на Java. Эти ресурсы были полезны для меня. Вытяните вещи, как ваши.sbt настройки из образца.
Сначала прочитайте обзор высокого уровня. Во-вторых, клонировать образец и запускать его. Это SO при запуске полезно. В-третьих, перенесите код из образца в локальное дерево. Как только вы это сделаете, вы увидите, что нет стиля. См. Это для информации о том, как получить css/js.
Ну... libraryDependencies
- это SettingKey[ Seq[ ModuleId ] ]
.
Теперь SettingKey[ Seq[ ModuleId ] ]
можно рассматривать как нечто похожее на Seq
или List
и обеспечивает аналогичные функции.
Итак... вы можете просто добавить к нему свои новые зависимости, так же, как вы добавите в любой другой Seq
или List
.
libraryDependencies += "ws.securesocial" %% "securesocial" % "2.1.4"