grails 的登陆 退出 过滤
1、 现在我们需要为系统设计一个登录页面,使得访问任何需要登录的页面时都会呈现以下页面:
只有当用户登录成功后,才会跳转到先前要访问的页面。
2、 新建域类LoginUser:
LoginUser用于保存登录用户的相关信息,比如帐号和密码。
class LoginUser {//域:登陆用户
static constraints = {
userId(length:6..8,unique:true)//帐号6-8位
password(length:6..8)//密码6-8位
name(nullable:false)//姓名不可为空
level(range:1..10)//用户级别分10级,够了吧?
}
String userId//用户名
String password//密码
String name//用户姓名
int level//用户权限级别
}
3、 为系统配置一个默认的系统管理员:
打开grails-app/conf/BootStrap.groovy,编辑init闭包(我们可以利用init闭包在系统一启动时做一些初始化的工作):
def init = { servletContext ->
final String BACK_ADMIN='admin'
if(!LoginUser.findByUserId(BACK_ADMIN)){
new LoginUser(userId:BACK_ADMIN,password:'admin88',name:'\u7BA1\u7406\u5458',level:10).save()
}
}
这样,只要系统一启动,就会自动添加admin用户,这样无论系统中有没有录入一个用户,我们都有一个admin的管理员帐号可用。
4、 新建登陆页面:
编辑grails-app/views/loginUser/login.gsp:
<g:form action="login" method="post" > |
|
…… |
|
<input type="text" id="userId" name="userId" value="${loginUserInstance?.userId}" maxlength="8"/> |
//用户名输入框 |
…… |
|
<input type="password" id="password" name="password" maxlength="8"/> |
//密码输入框 |
…… |
|
<input class="button" type="submit" value="登录" /> |
//若使用<g:submitButton>标签可能无法正常提交,原因不知 |
…… |
|
</g:form> |
|
5、 在loginuser控制器中定义登录/注销action
打开grails-app/controllers/LoginUserController.groovy:
def login={ |
//action:登录 |
if(request.method=='GET'){//清除session |
//若请求方式为get,呈现login.gsp |
session.userId=null |
|
session.level=null |
|
def loginUserInstance=new LoginUser() |
//定义一个空的LoginUser实例 |
}else{ |
//若请求参数为表单提交 |
def loginUserInstance=LoginUser.findByUserIdAndPassword( |
//从根据用户名密码查找已有的用户 |
params.userId,params.password) |
|
if(loginUserInstance){//添加session |
//若找到匹配的用户,进行登录 |
session.userId=params.userId |
//把用户名记入session |
session.level=loginUserInstance.level |
//把用户级别记入session |
def requestParams=session.originReqParams?session.originReqParams:[controller:'loginUser',action:'login'] |
//从session中取用户先前请求的控制器和action |
redirect(requestParams) |
//登录成功,转入用户先前请求的页面 |
}else{//登录帐号或密码错误 |
//若找不到匹配用户,登录失败 |
flash['message']='\u767B\u5F55\u5E10\u53F7\u6216\u5BC6\u7801\u9519\u8BEF' |
//显示登录失败信息 |
}}} |
//如果前面都没有转向,则这里呈现默认视图——登录页面login.gsp |
def logout={ |
//action:注销 |
session.userId=null |
//从session中删除用户名 |
session.level=null |
//从session中删除用户级别 |
flash['message']='\u6210\u529F\u9000\u51FA\u767B\u5F55' //成功退出登录 |
//显示成功注销消息 |
redirect(controller:'loginUser',action:'login') //转向登录页 |
//转向登录页面 |
} |
|
6、 定义拦截器
我们的要求是系统必须在用户登录后才能访问,用户未登录情况下,只能显示登录页面login.gsp。
这样我们需要一个拦截器,在任何action被处理之前,先处理拦截器指定的内容,比如登录。如果登录成功,返回true,则该action接下来被正常处理,否则返回false,接下来该action的处理被忽略。
由于基本上,所有的控制器都需要一个拦截器,而且这些拦截器需要进行的处理都差不多——都强制要求用户进行登录,所以我们先来定义一个基类BaseController。在这个基类中我们定义好所有拦截器都需要进行的处理,然后让所有的控制器来继承它就可以了。
运行create-controller Base,然后编辑BaseController.groovy:
class BaseController {
def auth(){ //定义一个 auth 方法
if(!session.userId){ //如果在session中找不到用户id-即未登录
//定义一个map对象
def originReqParams=[controller:controllerName,action:actionName]
originReqParams.putAll(params) //把用户此时请求的控制器和action放入map对象
session.originReqParams=originReqParams//把map放入session方便下次转向
redirect(controller:'loginUser',action:'login')//调用登录页面要求用户登录
return false //返回false,则忽略用户原先请求的action
} }}
然后让所有的控制器都继承BaseController。这样所有的控制器都有一个叫auth的方法可用了。
在所有的控制器中加入:
def beforeInterceptor = [action:this.&auth]
这定义了一个简单的前置拦截器(即在action被处理之前触发)。它简单的要求所有的action被处理之前,先调用auth方法(注意这里使用了指针语法&符号)。
此外,在loginUser控制器中加入拦截器的是:
def beforeInterceptor=[action:this.&auth,except:['login']]
当然,这个拦截器在拦截action时,把login排除在外(因为对用户的登录动作要求行强制的登录本身就是多余的)。
现在,我们可以尝试访问所有的controller和action,如果我们没有事先登录,则所有的请求都会转到登录页面。只有当我们输入用户名密码进行登录之后,才会转入我们要访问的action。
7、 由于我们要求用户一开始访问系统时,显示的就是产品编号列表,则我们应该修改系统首页:
打开grails-app/views/index.gsp,在其中加入:
<%
response.sendRedirect(request.getContextPath()+"/productionNo/index");
%>
则当用户访问http://localhost:8080/IronwareProcess这个地址看到的将是登录页面,等用户登录后,才显示产品编号列表: