Oi Igor,
o Acegi gera um formulário de login pra você que pode ser customizado. Uma solução seria você interceptar as requisições feitas por este formulário usando um filter e, neste, passar o login para maiúscula (ou minúscula se for o caso) para, em seguida, enviar para a action que efetua a autenticação pra você.
Oi Henrique, eu tentei fazer isso, mas eu não acho no LoginController aonde ele pega o username digitado na pagina de login e faz a autenticação....
Olha a auth.gsp:
<body>
<div id='login'>
<div class='inner'>
<g:if test='${flash.message}'>
<div class='login_message'>${flash.message}</div>
</g:if>
<div class='fheader'>Please Login..</div>
<form action='${postUrl}' method='POST' id='loginForm' class='cssform'>
<p>
<label for='j_username'>Login ID</label>
<input type='text' class='text_' name='j_username' id='j_username' value='${request.remoteUser}' />
</p>
<p>
<label for='j_password'>Password</label>
<input type='password' class='text_' name='j_password' id='j_password' />
</p>
<p>
<label for='remember_me'>Remember me</label>
<input type='checkbox' class='chk' name='_spring_security_remember_me' id='remember_me'
<g:if test='${hasCookie}'>checked='checked'</g:if> />
</p>
<p>
<input type='submit' value='Login' />
</p>
</form>
</div>
</div>
<script type='text/javascript'>
E o loginController:
import org.codehaus.groovy.grails.plugins.springsecurity.RedirectUtils
import org.grails.plugins.springsecurity.service.AuthenticateService
import org.springframework.security.AuthenticationTrustResolverImpl
import org.springframework.security.DisabledException
import org.springframework.security.context.SecurityContextHolder as SCH
import org.springframework.security.ui.AbstractProcessingFilter
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter
/**
* Login Controller (Example).
*/
class LoginController {
/**
* Dependency injection for the authentication service.
*/
def authenticateService
/**
* Dependency injection for OpenIDConsumer.
*/
def openIDConsumer
/**
* Dependency injection for OpenIDAuthenticationProcessingFilter.
*/
def openIDAuthenticationProcessingFilter
private final authenticationTrustResolver = new AuthenticationTrustResolverImpl()
def index = {
if (isLoggedIn()) {
redirect uri: '/'
}
else {
redirect action: auth, params: params
}
}
/**
* Show the login page.
*/
def auth = {
nocache response
if (isLoggedIn()) {
redirect uri: '/'
return
}
String view
String postUrl
def config = authenticateService.securityConfig.security
if (config.useOpenId) {
view = 'openIdAuth'
postUrl = "${request.contextPath}/login/openIdAuthenticate"
}
else if (config.useFacebook) {
view = 'facebookAuth'
postUrl = "${request.contextPath}${config.facebook.filterProcessesUrl}"
}
else {
view = 'auth'
postUrl = "${request.contextPath}${config.filterProcessesUrl}"
}
render view: view, model: [postUrl: postUrl]
}
/**
* Form submit action to start an OpenID authentication.
*/
def openIdAuthenticate = {
String openID = params['j_username']
try {
String returnToURL = RedirectUtils.buildRedirectUrl(
request, response, openIDAuthenticationProcessingFilter.filterProcessesUrl)
String redirectUrl = openIDConsumer.beginConsumption(request, openID, returnToURL)
redirect url: redirectUrl
}
catch (org.springframework.security.ui.openid.OpenIDConsumerException e) {
log.error "Consumer error: $e.message", e
redirect url: openIDAuthenticationProcessingFilter.authenticationFailureUrl
}
}
// Login page (function|json) for Ajax access.
def authAjax = {
nocache(response)
//this is example:
render """
<script type='text/javascript'>
(function() {
loginForm();
})();
</script>
"""
}
/**
* The Ajax success redirect url.
*/
def ajaxSuccess = {
nocache(response)
render '{success: true}'
}
/**
* Show denied page.
*/
def denied = {
if (isLoggedIn() && authenticationTrustResolver.isRememberMe(SCH.context?.authentication)) {
// have cookie but the page is guarded with IS_AUTHENTICATED_FULLY
redirect action: full, params: params
}
}
/**
* Login page for users with a remember-me cookie but accessing a IS_AUTHENTICATED_FULLY page.
*/
def full = {
render view: 'auth', params: params,
model: [hasCookie: authenticationTrustResolver.isRememberMe(SCH.context?.authentication)]
}
// Denial page (data|view|json) for Ajax access.
def deniedAjax = {
//this is example:
render "{error: 'access denied'}"
}
/**
* login failed
*/
def authfail = {
def username = session[AuthenticationProcessingFilter.SPRING_SECURITY_LAST_USERNAME_KEY]
def msg = ''
def exception = session[AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY]
if (exception) {
if (exception instanceof DisabledException) {
msg = "[$username] is disabled."
}
else {
msg = "[$username] wrong usuario/senha."
}
}
if (isAjax()) {
render "{error: '${msg}'}"
}
else {
flash.message = msg
redirect action: auth, params: params
}
}
/**
* Check if logged in.
*/
private boolean isLoggedIn() {
return authenticateService.isLoggedIn()
}
private boolean isAjax() {
return authenticateService.isAjax(request)
}
/** cache controls */
private void nocache(response) {
response.setHeader('Cache-Control', 'no-cache') // HTTP 1.1
response.addDateHeader('Expires', 0)
response.setDateHeader('max-age', 0)
response.setIntHeader ('Expires', -1) //prevents caching at the proxy server
response.addHeader('cache-Control', 'private') //IE5.x only
}
}
Não consigo entender aonde o controller pega o username digitado no login para transforma-lo em maiusculo.
Henrique,
Na página auth.gsp o action recebe /bookstore/j_spring_security_check
Mas aonde está isso??
Obrigado
Oi Igor,
de cabeça assim não me lembro, mas você pode seguir o procedimento abaixo pra descobrir: no diretório de trabalho do Grails (SEU_DIRETORIO_HOME/.grails/[versão do Grails]/projects/[seu projeto]) vá a pasta plugins.
Lá dentro estará presente todo o código fonte do Acegi. O controlador fica no local padrão da pasta plugin, que é o grails-app/controller. Se não me engano, ele tem uma única action.
O caminho do plugin pode variar um pouco em versões mais antigas que o ramo 1.3, mas o procedimento básico é este.
Olá Henrique,
Tem somente um controller: AuthBase.groovy
package org.grails.plugins.springsecurity.controller^M
import org.grails.plugins.springsecurity.service.AuthenticateService^M
import org.springframework.security.context.SecurityContextHolder as SCH^M
import org.springframework.web.servlet.support.RequestContextUtils as RCU^M
/**^M
* [Example] Controllers Base class for to use Spring Security (authentication and authorization).^M
class AuthBase {^M
^M
/** Authenticate Service */^M
def authenticateService^M
^M
/** Authenticated user domain instance */^M
def loginUser^M
^M
/** is user logged on or not */^M
boolean logon^M
^M
/** principal */^M
def authPrincipal^M
^M
/** is Admin */^M
boolean isAdmin^M
^M
/** Locale */^M
Locale locale^M
^M
/** main request permission setting */^M
def requestAllowed^M
def beforeInterceptor = {^M
if (requestAllowed != null && !authenticateService.ifAnyGranted(requestAllowed)) {^M
println 'request not allowed: ' + requestAllowed^M
redirect(uri: '/')^M
return^M
}^M
^M
authPrincipal = SCH?.context?.authentication?.principal^M
if (authPrincipal != null && authPrincipal != 'anonymousUser') {^M
loginUser = authPrincipal?.domainClass^M
logon = true^M
isAdmin = authenticateService.ifAnyGranted('ROLE_SUPERVISOR')^M
}^M
^M
/* i18n: if lang params */^M
if (params['lang']) {^M
locale = new Locale(params['lang'])^M
RCU.getLocaleResolver(request).setLocale(request,response,locale)^M
session.lang = params['lang']^M
}^M
/* need this for jetty */^M
if (session.lang != null) {^M
locale = new Locale(session.lang)^M
RCU.getLocaleResolver(request).setLocale(request,response,locale)^M
}^M
if (locale == null) {^M
locale = RCU.getLocale(request)^M
}^M
^M
/* cache */^M
response.setHeader('Cache-Control','no-cache') // HTTP 1.1^M
response.setDateHeader('max-age', 0) ^M
response.setIntHeader ('Expires', -1) //prevents caching at the proxy server ^M
response.addHeader('cache-Control', 'private') //IE5.x only^M
}^M
}^M
******
Eu posso alterar essa classe?
É nessa classe que eu altero para maiúsculo o login?
Seria a variavel loginUser ?
Obrigado,
..
Oi Igor, não é recomendavel que você altere esta classe. Caso queira, o ideal é que você altere no próprio código fonte do plugin e o reempacote novamente. Lembre-se que qualquer alteração no seu diretório de trabalho do Grails vai ser perdida no primeiro comando "grails clean" que você executar.
Olá Henrique,
Não é essa classe que postei, analisei melhor e é na classe GrailsDaoImpl.groovy que precisa da alteração, que é bem simples, colocar o toUpperCase(username.toUpperCase).
Essa classe fica no caminho:
/home/igordami/.grails/1.3.7/projects/bookstore/plugins/acegi-0.5.3.2/src/groovy/org/codehaus/groovy/grails/plugins/springsecurity/GrailsDaoImpl.groovy
Henrique, eu fiz a alteração na classe GrailsDaoImpl.groovy e testei e funcionou.
Mas fiquei com dúvidas que você disse que quando eu der o "grails clean" ele vai perder as alterações que eu fiz. Vou perder o que eu fiz na classe GrailsDaoImpl.groovy?
Se não for perder as alterações, tudo bem, mas se for perder as alterações, por favor, me explique como eu faço para reempacotar o novamente?
Obrigado
Henrique,
Uma dúvida:
Executando o grails clean, ele limpa os diretórios e arquivo abaixo:
[delete] Deleting: /home/igordami/.grails/1.3.7/projects/bookstore/resources/web.xml
[delete] Deleting directory /home/igordami/ldap_teste/bookstore/target/classes
[delete] Deleting directory /home/igordami/.grails/1.3.7/projects/bookstore/plugin-classes
[delete] Deleting directory /home/igordami/.grails/1.3.7/projects/bookstore/resources
Mas a classe GrailsDaoImpl.groovy que alterei, não fica no caminho que foi limpado:
/home/igordami/.grails/1.3.7/projects/bookstore/plugins/acegi-0.5.3.2/src/groovy/org/codehaus/groovy/grails/plugins/springsecurity/GrailsDaoImpl.groovy
Quando eu gerar o pacote .war da aplicação, ele vai levar essa alteração que fiz na classe GrailsDaoImpl.groovy?
Obrigado,
Oi Igor, neste caso, ele irá levar para o war.
Mas eu não recomendo de modo algum você alterar o código fonte do plugin que se encontra nesta pasta, pois é conteúdo volátil.
Minha sugestão é a seguinte: se for para de fato alterar o plugin, você deve seguir o seguinte procedimento.
1. Baixe o código fonte do plugin e altere-o em um diretório qualquer
2. Feita a edição, execute o comando grails package-plugin. Ele vai gerar um arquivo .zip se não me engano
3. Instale o plugin alterado na sua aplicação com o comando grails install-plugin [caminho pro .zip]
Assim você não vai perder o seu código fonte alterado caso seu workdir seja apagado.
Oi Henrique,
Fiz isso que você falou.
Baixei o código fonte, alterei, gerei o pacote do plugin e instalei ele na aplicação.
Funcionou bem.
Muito obrigado pela ajuda.
Abs