Java for Web学习笔记(六九):Service和Repository(4)Principal
来源:互联网 发布:python写淘宝秒杀脚本 编辑:程序博客网 时间:2024/06/05 02:57
什么是Principal
java.security.Principal,顾名思义和安全有关,但目前我们仅用其最最基本的含义,以后会进一步学习。
JAAS所使用的认证方案以两种非常重要的实体为基础:principal和subject。实际被认证的人或者服务称为subject。principal是一个惟一的实体,比如个人或者组的名字、帐号、社会安全号或者类似的惟一标识。为了惟一标识一个subject(这是认证的关键部分),一个或者多个principal必须与这个subject相关联。[1]
HttpServletRequest提供getUserPrincipal()来获取,其返回值通过HttpSerlvetRequestWrapper来设定。
在小例子中,我们将存放在session中的username放在请求的principal中,方便获取。
自定义所需的Principal
小例子中,用户的关键信息就是用户名。Pincipal是个接口,需要实现getName()。为了方便比对两个principal是否相同(本例就是用户名,而不是对象地址),重写了Object类的equals(为此重写了hashcode),我们还允许clone。public class UserPrincipal implements Principal, Cloneable, Serializable{ private static final long serialVersionUID = 1L; //这是Serializable要求给出,小例子不存在传输和读写在其他介质,可以不用Serializable。 //【1】小例子中最重要的身份信息是username,该信息一次性填入,不允许修改 private final String username; public UserPrincipal(String username) { this.username = username; } //【2】getName()是Principal接口,是主要使用的方法 @Override public String getName() { return this.username; } //【3】hashCode()和equals()即是Principal接口也是Object的接口,我们比对两个principal是否一直,不是比较对象的地址,而是里面的信息。同时修改toString()给出显示的信息 @Override public int hashCode() { return this.username.hashCode(); } @Override public boolean equals(Object obj) { return obj instanceof UserPrincipal && ((UserPrincipal) obj).username.equals(this.username); } @Override public String toString() { return this.username; } //【4】允许colon @Override protected UserPrincipal clone() throws CloneNotSupportedException { return (UserPrincipal)super.clone(); } //【5】提供两个静态方法getPrincipal()和setPrincipal(),将principal和session中的某个属性对应起来,也就是真实的仍借用session进行数据存放。放置在session,session过期后,将不存在 public static Principal getPrincipal(HttpSession session){ return session == null ? null : (Principal)session.getAttribute("cn.wei.flowingflying.customer_support.user.principal"); } public static void setPrincipal(HttpSession session, Principal principal){ session.setAttribute("cn.wei.flowingflying.customer_support.user.principal", principal); }}
小例子:用principal存放应用信息并进行auth
设置认证服务接口:AuthenticationService
public interface AuthenticationService { /** 如果认证成功,返回principal对象,失败,返回null */ Principal authenticate(String username, String password);}
设置认证控制器:login相关的Controller
@Controllerpublic class AuthenticationController { @Inject private AuthenticationService authenticationService; @RequestMapping(value="login",method=RequestMethod.GET) public ModelAndView login(Map<String,Object> model,HttpSession session){ //【1】如果存在principal,说明已经登录了,进入主界面。通过filter的处理(见紧接),我们也可以通过request.getPrincipal()来获取该值。 if(UserPrincipal.getPrincipal(session) != null) return getHome(); model.put("loginFailed", false); model.put("loginForm",new Form()); return new ModelAndView("login"); } @RequestMapping(value = "login", method = RequestMethod.POST) public ModelAndView login(Map<String,Object> model,HttpSession session,HttpServletRequest request,Form form){ //【2】进行身份校验,获取principal Principal principal = this.authenticationService.authenticate(form.getUsername(), form.getPassword()); // 2.1)如果校验失败 if(principal == null){ logger.warn("Login failed for user {}",form.getUsername()); form.setPassword(null); model.put("loginFailed", false); model.put("loginForm", form); return new ModelAndView("login"); } // 2.2)如果校验成功,设置principal UserPrincipal.setPrincipal(session, principal); request.changeSessionId(); return getHome(); } ......}
允许request.getUserPrincipal()获取:AuthenticationFilter
AuthenticationFilter有两个作用:
- 我们应对每个HTTP请求(除了静态资源,如图片,css文件)进行用户身份认证检查,采用Filter的方式。
- 封装request,支持request.getUserPrincipal()操作。
public class AuthenticationFilter implements Filter { ... ... public void doFilter(ServletRequest request,ServletResponse response, FilterChain chain) throws IOException,ServletException{ //【1】获取principal HttpSession session = ((HttpServletRequest)request).getSession(false); final Principal principal = UserPrincipal.getPrincipal(session); //【2】如果principal为null(未登录),进入登录界面 if(principal == null){ ((HttpServletResponse)response).sendRedirect( ((HttpServletRequest)request).getContextPath() + "/login"); }else{ //【3】如果principal存在(已登录),我们希望能从request中直接获取principal信息。通过wrapper request,给出getUserPrincipal()的返回 chain.doFilter( new HttpServletRequestWrapper((HttpServletRequest)request){ @Override public Principal getUserPrincipal() { return principal; } },response); } } }
在LoggingFilter中使用principal
我们为了让log4j2在log中%X{username}给出登录用户名,写了LoggingFilter,在里面通过principal获取。在BootStrap中LoggingFilter是位于AuthenticationFilter之前,所有采用request.getUserPrincipal()没有效果,需要通过UserPrincipal的静态方法来获取。
public class LoggingFilter implements Filter { ... ... public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 如果LoggingFilter在AuthenticationFilter之前先执行,则无法使用request.getPrincipal()的处理。然而我们提供了从session中获取的静态方法,可以方便获得 Principal principal = UserPrincipal.getPrincipal(((HttpServletRequest)request).getSession(false)); if(principal != null){ ThreadContext.put("username", principal.getName()); } try{ chain.doFilter(request, response); }finally{ ThreadContext.clearAll(); } }}
相关链接: 我的Professional Java for Web Applications相关文章
阅读全文
0 0
- Java for Web学习笔记(六九):Service和Repository(4)Principal
- Java for Web学习笔记(六六):Service和Repository(1)抽象分层
- Java for Web学习笔记(六八):Service和Repository(3)异步Async和调度Schedule
- Java for Web学习笔记(六七):Service和Repository(2)抽象分层例子
- Java for Web学习笔记(七十):Service和Repository(5)回调处理Consumer
- Java for Web学习笔记(七一):Service和Repository(6)在Spring框架中使用Listener
- Java for Web学习笔记(七二):Service和Repository(7)在Spring框架中使用WebSocket
- Java for Web学习笔记(九六):持久化初探(1)数据存储
- Java for Web学习笔记(六三):Controller替代Servlet(5)Model和View
- Java for Web学习笔记(八六):消息和集群(1)一般性了解
- Java for Web学习笔记(九九):持久化初探(4)JPA小例子(下)
- Java for Web学习笔记(六):Servlet(4)HttpServletResponse
- Java for Web学习笔记(三六):自定义tag(4)自定义Tag文件
- Java for Web学习笔记(六二):Controller替代Servlet(4)方法返回值
- Java for Web学习笔记(七六):国际化i18n(4)其他
- Java for Web学习笔记(九二):消息和集群(7)RabbitMQ和消息模式(上)
- Java for Web学习笔记(九三):消息和集群(8)RabbitMQ和消息模式(中)
- Java for Web学习笔记(九四):消息和集群(9)RabbitMQ和消息模式(下)
- python中的type()和isinstance()
- Log4j之HelloWorld
- Hadoop基础教程-第8章 Zookeeper(8.5 Zookeeper内存数据库)(草稿)
- GDOI模拟7.8-7.16 总结
- 极值栈的设计—以最小栈为例
- Java for Web学习笔记(六九):Service和Repository(4)Principal
- STM32Cube库的使用
- Linux2.6--进程抢占和上下文切换
- 持续集成之jenkins实践教程:基础篇(5): 集成docker
- Go语言实战--并发示例-Pool
- 列表和按钮
- 如何训练深度神经网络?老司机的15点建议
- Angular中的内置指令
- 过滤器和拦截器的区别