Módulo Secure
El módulo Secure es uno de los módulos que vienen por defecto con la distribución de Play. Permite añadir login mediante usuario y contraseña a nuestra aplicación.
Instalación
Añadimos las dependencias del módulo de seguridad
conf/dependencies.yml
require:
- play
- play -> secure
1
2
3
4
5
# Application dependencies
Ejecutamos en la terminal
play dependencies
play eclipsify
Añade las rutas por defecto conf/routes
* / module:secure
Importante Cada vez que añadas una nueva librerías deberás reiniciar el servidor
Uso
Anota el controlador al que quieras ponerle restricción de seguridad con la anotación @With(Secure.class)
@With(Secure.class)
public class Timeline extends Controller {
…
}
1
2
3
4
5
6
7
package controllers;
…
Ahora cuando accedes a http://localhost:9000/ nos redireccionará a la página de login http://localhost:9000/login
Personalizando la autenticación
Para personalizar el mecanismo de autenticación debemos crear una clase que extienda de Secure.Security y sobreescribir el método authenticate
public class Security extends Secure.Security {
static boolean authenticate(String username, String password) {
User user = User.find(“byUsername”, username).first();
return user != null && user.password.equals(password);
} }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package controllers;
import models.User;
<span class="kd">static</span> <span class="n">User</span> <span class="nf">userConnected</span><span class="o">(){</span>
<span class="n">User</span> <span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="na">find</span><span class="o">(</span><span class="s">"byUsername"</span><span class="o">,</span> <span class="n">session</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="s">"username"</span><span class="o">)).</span><span class="na">first</span><span class="o">();</span>
<span class="k">return</span> <span class="n">user</span><span class="o">;</span>
<span class="o">}</span>
Prueba a hacer login con algunos de los usuarios definido en initial-data.yml
Usuario conectado y logout
Vamos a modificar la plantilla para mostrar el usuario que está conectado y ponerle un botón que le permita desconectarse de la aplicación.
app/views/main.hml
1
2
3
<form action=“@{Secure.logout}” class=“pull-right”>
<button class=“btn” type=“submit”>${controllers.Security.userConnected().username} - Salir</button>
</form>
Personalizando la página de login
Para personalizar la página de login lo único que tenemos que hacer es crear una nueva vista que esté en la misma ruta que la vista del módulo. Si nos fijamos en el proyecto de Eclipse tenemos un enlace al proyecto secure (aparece una carpeta de código con una flecha). En el proyecto tenemos la vista views.Secure.login.html que es la que muestra la pantalla de login. Lo que devemos hacer es crear una vista, dentro de nuestro proyecto, que esté en la misma ruta.
Basándonos en la vista original y aplicandole algunos estilos de twitter bootstrap tenemos esto
app/views/Secure/login.html
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
<meta charset=“utf-8”>
<link rel=“shortcut icon” type=“image/png” href=“@{‘/public/images/favicon.png’}”>
<script src=“@{‘/public/javascripts/jquery-1.5.2.min.js’}” type=“text/javascript” charset=“${_response_encoding}”></script>
<link rel=“stylesheet” href=“http://twitter.github.com/bootstrap/1.3.0/bootstrap.min.css”>
<link rel=“stylesheet” media=“screen” href=“@{‘/public/stylesheets/main.css’}”>
</head>
<body style=“padding: 0”>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"container"</span> <span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"content"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"page-header"</span><span class="nt">></span>
<span class="nt"><h1></span>Login<span class="nt"></h1></span>
<span class="nt"></div></span>
<span class="nt"><div></span>
#{form @authenticate()}
#{if flash.error}
<span class="nt"><p</span> <span class="na">class=</span><span class="s">"alert-message error"</span><span class="nt">></span>
<span class="err">&</span>{flash.error}
<span class="nt"></p></span>
#{/if}
#{if flash.success}
<span class="nt"><p</span> <span class="na">class=</span><span class="s">"alert-message success"</span><span class="nt">></span>
<span class="err">&</span>{flash.success}
<span class="nt"></p></span>
#{/if}
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"clearfix"</span><span class="nt">></span>
<span class="nt"><label</span> <span class="na">for=</span><span class="s">"username"</span><span class="nt">></span><span class="err">&</span>{'secure.username'}<span class="nt"></label></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"input"</span><span class="nt">></span>
<span class="nt"><input</span> <span class="na">class=</span><span class="s">"xlarge"</span> <span class="na">id=</span><span class="s">"username"</span> <span class="na">name=</span><span class="s">"username"</span> <span class="na">size=</span><span class="s">"30"</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">value=</span><span class="s">"${flash.username}"</span> <span class="nt">/></span>
<span class="nt"></div></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"clearfix"</span><span class="nt">></span>
<span class="nt"><label</span> <span class="na">for=</span><span class="s">"password"</span><span class="nt">></span><span class="err">&</span>{'secure.password'}<span class="nt"></label></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"input"</span><span class="nt">></span>
<span class="nt"><input</span> <span class="na">class=</span><span class="s">"xlarge"</span> <span class="na">id=</span><span class="s">"password"</span> <span class="na">name=</span><span class="s">"password"</span> <span class="na">size=</span><span class="s">"30"</span> <span class="na">type=</span><span class="s">"password"</span> <span class="na">value=</span><span class="s">""</span> <span class="nt">/></span>
<span class="nt"></div></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"input"</span><span class="nt">></span>
<span class="nt"><ul</span> <span class="na">class=</span><span class="s">"inputs-list"</span><span class="nt">></span>
<span class="nt"><li><label></span>
<span class="nt"><input</span> <span class="na">type=</span><span class="s">"checkbox"</span> <span class="na">name=</span><span class="s">"optionsCheckboxes"</span> <span class="na">value=</span><span class="s">"true"</span> <span class="err">${</span><span class="na">flash</span><span class="err">.</span><span class="na">remember</span> <span class="err">?</span> <span class="err">'</span><span class="na">checked=</span><span class="s">"true"</span><span class="err">'</span> <span class="na">:</span> <span class="err">''}</span><span class="nt">></span>
<span class="nt"><span></span><span class="err">&</span>{'secure.remember'}<span class="nt"></span></span>
<span class="nt"></label></li></span>
<span class="nt"></ul></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"input"</span><span class="nt">></span>
<span class="nt"><input</span> <span class="na">type=</span><span class="s">"submit"</span> <span class="na">class=</span><span class="s">"btn primary"</span> <span class="na">value=</span><span class="s">"&{'secure.signin'}"</span><span class="nt">></span>
<span class="nt"></div></span>
#{/form}
<span class="nt"></div></span>
<span class="nt"></div></span>
<span class="nt"><footer></span>
<span class="nt"><p></span>
<span class="nt"><a</span> <span class="na">href=</span><span class="s">"http://axelhzf.github.com/play-curso/"</span><span class="nt">></span>Tutorial<span class="nt"></a></span> - <span class="nt"><a</span>
<span class="na">href=</span><span class="s">"https://github.com/axelhzf/play-curso"</span><span class="nt">></span>Código fuente<span class="nt"></a></span>
<span class="nt"></p></span>
<span class="nt"></footer></span>
<span class="nt"></div></span>
<span class="c"><!-- /container --></span>
Ejercicios: Añadir comprobación adicional
Vamos a establecer algunos usuarios administrador, que tendrán más privilegios que otros. Por ejemplo, los usuarios administradores serán los únicos capaces de ver la página de las estadísticas.
- Modifica el modelo añadiendo a los usuario un atributo booleano que indique si es administrador o no.
- Busca en la documentación del módulo de seguridad http://www.playframework.org/documentation/1.2.3/secure cómo añadir comprobaciones adicionales con la anotacion @Check. En la sección “Adding authorization check ”. La página de estadísticas sólo la podrán ver los administradores.
- Modifica el fichero initial-data.yml para poner al user1 y al user2 como administradores.
- Comprueba que tienes acceso con los usuarios adecuados y no con los demás.
- Modifica la plantilla que a los usuarios que no son administradores no les aparezca el enlace en el menú a la página de las estadísticas.
Consejos:
- Puede que en la documentación no esté, pero existe un tag para hacer las comprobaciones que hace check. Búscalo en el código fuente.
Solución
Modifica la entidad User
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.ManyToMany;
import play.db.jpa.Model; @Entity
public class User extends Model { }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package models;
<span class="kd">public</span> <span class="n">String</span> <span class="n">username</span><span class="o">;</span>
<span class="kd">public</span> <span class="n">String</span> <span class="n">password</span><span class="o">;</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="n">admin</span><span class="o">;</span>
<span class="nd">@ManyToMany</span>
<span class="kd">public</span> <span class="n">List</span><span class="o"><</span><span class="n">User</span><span class="o">></span> <span class="n">follows</span><span class="o">;</span>
<span class="kd">public</span> <span class="nf">User</span><span class="o">(</span><span class="n">String</span> <span class="n">username</span><span class="o">,</span> <span class="n">String</span> <span class="n">password</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">super</span><span class="o">();</span>
<span class="k">this</span><span class="o">.</span><span class="na">username</span> <span class="o">=</span> <span class="n">username</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">password</span> <span class="o">=</span> <span class="n">password</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">admin</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="n">follows</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ArrayList</span><span class="o"><</span><span class="n">User</span><span class="o">>();</span>
<span class="o">}</span>
Añade la anotación @Check en el método que renderiza la página de las estadísticas
1
2
@Check(“isAdmin”)
public static void stats(){
Implementa la comprobación “isAdmin”
1
2
3
4
5
6
7
8
static boolean check(String profile) {
User user = userConnected();
if (“isAdmin”.equals(profile)) {
return user.admin;
} else {
return false;
}
}
Modifica la plantilla para ocultar el enlace a la página de estadísticas si el usuario no es administrador.
1
2
3
#{secure.check ‘isAdmin’}
<li><a href=“@{Timeline.stats}”>Estadísticas</a></li>
#{/secure.check}