似乎无法创建一种从Java为Devise插入用户的功能方法。目前有以下领域: “_ID”, “访问权限”, “confirmation_sent_at” “confirmation_token” “confirmed_at” “电子邮件”, “encrypted_password” “sign_in_count”
我能够插入一个计为用户的文档。问题是,当我去: http://www.mysite.com:3000/users/confirmation?confirmation_token=TOKENHERE
我收到一条消息,说它无效。
编辑1: 当我重新发送此用户(生成新令牌)的确认说明时,用户可以登录。这证实了我对令牌成为问题的怀疑。如何将Devise的令牌生成器移植到Java?
编辑2: 当我在网站上注册时,它说我应该检查确认链接。但是,如果我进入Mongo shell,请手动取出确认令牌并将其粘贴到site.com/users/confirmation?confirmation_token=然后它不起作用!但是,如果我确实使用了我发送的确认链接,它就可以了。如何从Java创建一个VALID标记。请帮忙!
答案 0 :(得分:0)
对于此quoestion,您应该参考this stackoverflow answer和protect_from_forgery的Rails API。
简短的回答是禁用控制器中的伪造保护,但这会使您的应用程序容易受到CSRF攻击:
skip_before_action :verify_authenticity_token
更好的方法是使用JSON或XML请求进行身份验证,因为这些请求不受CSRF保护。您可以找到设计here的解决方案。
Monkey patch设计用于保存未编码的确认令牌。在你的config / initializers / devise.rb
中module Devise
module Models
module Confirmable
def generate_confirmation_token
raw, enc = Devise.token_generator.generate(self.class, :confirmation_token)
@raw_confirmation_token = raw
self.my_unencoded_column = raw # Patch
self.confirmation_token = enc
self.confirmation_sent_at = Time.now.utc
end
end
end
end
答案 1 :(得分:0)
如果其他人发现自己试图让一个java或scala应用程序与rails应用程序共存,我就破解了以下内容。它在scala但使用java apis所以应该很容易阅读。据我所知,它复制了Devise的行为,如果我点击rails app中的确认链接与原始令牌rails / devise生成相同的编码字符串。
import java.security.spec.KeySpec
import javax.crypto.SecretKey
import javax.crypto.SecretKeyFactory
import javax.crypto.spec.PBEKeySpec
import javax.crypto.spec.SecretKeySpec
import javax.crypto.Mac
import javax.xml.bind.DatatypeConverter
import java.util.Base64
// copy functionality from Rails Devise
object TokenGenerator {
// sample values 9exithzwZ8P9meqdVs3K => 54364224169895883e87c8412be5874039b470e26e762cb3ddc37c0bdcf014f5
// 5zNMi6egbyPoDUy2t3NY => 75bd5d53aa36d3fc61ac186b4c6e2be8353e6b39536d3cf846719284e05474ca
private val deviseSecret = sys.env("DEVISE_SECRET")
private val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
val encoder = Base64.getUrlEncoder()
case class TokenInfo(raw: String, encoded: String)
def createConfirmationToken: TokenInfo = {
// copy behavior from rails world. Don't know why it does this
val replacements = Map('l' -> "s", 'I' -> "x", 'O' -> "y", '0' -> "z")
// make a raw key of 20 chars, doesn't seem to matter what they are, just need url valid set
val bytes = new Array[Byte](16)
scala.util.Random.nextBytes(bytes)
val raw = encoder.encodeToString(bytes).take(20).foldLeft(""){(acc, x) => acc ++ replacements.get(x).getOrElse(x.toString)}
TokenInfo(raw, digestForConfirmationToken(raw))
}
private def generateKey(salt: String): Array[Byte] = {
val iter = 65536
val keySize = 512
val spec = new PBEKeySpec(deviseSecret.toCharArray, salt.getBytes("UTF-8"), iter, keySize)
val sk = factory.generateSecret(spec)
val skspec = new SecretKeySpec(sk.getEncoded, "AES")
skspec.getEncoded
}
def sha256HexDigest(s: String, key: Array[Byte]): String = {
val mac = Mac.getInstance("HmacSHA256")
val keySpec = new SecretKeySpec(key, "RAW")
mac.init(keySpec)
val result: Array[Byte] = mac.doFinal(s.getBytes())
DatatypeConverter.printHexBinary(result).toLowerCase
}
private def getDigest(raw: String, salt: String) = sha256HexDigest(raw, generateKey(salt))
// devise uses salt "Devise #{column}", in this case its confirmation_token
def digestForConfirmationToken(raw: String) = getDigest(raw, "Devise confirmation_token")
}