Shiro
Shiro is an open source project under Apache, we call it Apache Shiro. It is a very easy-to-use security framework with Java projects, providing authentication, authorization, encryption, and session management. Like spring Security, it is a permission security framework. However, compared with Spring Security, Shiro uses a relatively simple, easy-to-understand and easy-to-use authorization method. Shiro is a lightweight framework. It is much simpler than security and is not as complicated as security. For more detailed introductions, you can basically learn from its official website (http://shiro.apache.org/) that it mainly provides the following functions:
(1) Authentication (authentication)
(2) Authorization (authorization)
(3) Session Management (session management)
(4) Cryptography (encryption)
First of all, the authentication service, that is, through her, you can complete the identity authentication, allowing her to determine whether the user is a real member.
Secondly, authorized service, to put it bluntly, is "access control" service, that is, let her identify what permissions the user has. To put it bluntly, it is to give him what operation permissions by judging what role the user is.
Then, there is the session management service. At this time, an independent Session management framework is different from the Http Session we are familiar with.
Finally, she also provides Cryptography (encryption) services, encapsulating many cryptographic algorithms.
Today, I won’t say all about it, and focus on her conversation management function. In fact, this is something that almost all webs should be involved.
Before talking about shiro's session management service, let's review how we did the previous session management.
1. At first we directly used the Http Session mechanism of the web server. That is, if the user comes in for the first time, the web container will create a session for the request, and then store the session. By passing the corresponding sessionId as a cookie to the client.
If the client sends a request to this server again, the sessionId will be automatically brought over. Then the web server will determine whether the session is still in memory based on the sessionId brought by the client (the session has an expiration time and can be configured in the web.xml file). If the corresponding session cannot be found, it means that the session expiration time has passed. At this time, the web server will create a session for it again, and then pass the new sessionId to the client as before.
Therefore, we can use this mechanism to manage the user's login session in the program. For example, after the user's first login is successful, we store the user's basic information in the session (for example: session.setAttribute("user", "userInfo") ). The next time the user visits again, we obtain the user information in the current session based on the user information
( session.getAttribute("user") ) to determine whether the user has expired. If it cannot be obtained, the user will be prompted to log in again.
2. The second method is to transfer the place where information is stored to third-party media, such as cache, memecache or Redis. This method is mainly adopted because of the emergence of distributed systems.
In this case, we need to generate the sessionId ourselves. Generally, we will use a defined prefix ( user:login:token ) and add userid, or timestamp. Then we will use this sessionId as the cache key, and the user's information as value, and store it in the cache, and set the invalidation time:
jedisClient.set(tokenKey, JsonUtil.toJSONString(userInfo)); jedisClient.expire(tokenKey, TOKEN_LOSE_SECONDS);
We also need to pass the generated tokenKey to the client through cookies: CookieUtils.setCookie(request, response, "TT_TOKEN", tokenKey);
In this way, when the user visits the next time (defines an interceptor), we can take out the corresponding tokenKey from the cookie, and then use this tokenKey to go to the cache to retrieve the corresponding value. If it cannot be obtained, it means that the key has expired and the user is prompted to log in again.
Note: tokenKey is important, it is the hub connecting the cache side and the client.
3. The last one is our shiro method, and the idea is similar. The code is quite simple, so I will just upload the code:
1) Create a new applicationContext-shiro.xml file:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"> <bean id="shiroFilter"> <property name="securityManager" ref="securityManager"></property> <property name="loginUrl" value="/loginPage"></property> <property name="unauthorizedUrl" value="/pages/unauthorized.jsp"/> <property name="filterChainDefinitions"> <value> /jcaptcha* = anon /logout = anon </value> </property> </bean> <bean> <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"></property> <property name="arguments" ref="securityManager"></property> </bean> <bean id="securityManager"> <property name="cacheManager" ref="cacheManager"></property> <property name="sessionManager" ref="sessionManager"></property> </bean> <bean id="sessionManager"> <property name="sessionDAO" ref="sessionDAO"></bean> //This class needs to be implemented by itself<bean id="cacheManager"></bean></beans>
2) Configure the corresponding filter in web.xml:
<filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
3) Write an implementation class, inherit AbstractSessionDAO, and implement the corresponding method.
package com.jdd.core.shiro;import com.smart.core.redis.RedisManager;import org.apache.shiro.session.Session;import org.apache.shiro.session.UnknownSessionException;import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.util.SerializationUtils;import java.io.*;import java.util.ArrayList;import java.util.Collection;public class MySessionDAO extends AbstractSessionDAO { @Autowired private RedisManager redisManager; @Override public void update(Session session) throws UnknownSessionException { redisManager.set(SerializationUtils.serialize(session.getId().toString()), SerializationUtils.serialize(session)); redisManager.expire(SerializationUtils.serialize(session.getId().toString()), 60); } @Override public void delete(Session session) { redisManager.del(SerializationUtils.serialize(session.getId().toString())); } @Override public Collection<Session> getActiveSessions() { return new ArrayList<Session>(); } @Override protected Serializable doCreate(Session session) { //This is when you first access, create sessionId Serializable sid = this.generateSessionId(session); assignSessionId(session, sid); redisManager.set(SerializationUtils.serialize(session.getId().toString()), SerializationUtils.serialize(session)); redisManager.expire(SerializationUtils.serialize(session.getId().toString()), 60); return sid; } @Override protected Session doReadSession(Serializable serializable) { //This method is actually to read the session through sessionId. Each time you read it, the failure time must be reset byte[] aa = redisManager.get(SerializationUtils.serialize(serializable.toString())); Session session = (Session) SerializationUtils.deserialize(aa); redisManager.set(SerializationUtils.serialize(serializable.toString()), SerializationUtils.serialize(session)); redisManager.expire(SerializationUtils.serialize(serializable.toString()), 60); return session; } }4) The next step is to get the session of shiro in the logic after successful login, and then set the user information in
package com.smart.controller;import com.smart.pojo.User;import com.smart.service.UserService;import org.apache.shiro.SecurityUtils;import org.apache.shiro.mgt.SecurityManager;import org.apache.shiro.subject.Subject;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.steretype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;@Controller@RequestMapping("/user")public class UserController { @Autowired private UserService userService; @Autowired private SecurityManager sm; //Inject SecurityManager private Logger logger = LoggerFactory.getLogger(UserController.class); @RequestMapping(value = "/loginPage") public String loginPage(){ return "user/userLogin"; } @RequestMapping(value = "/userLogin", method = RequestMethod.POST) public String userLogin(@RequestParam(value="name") String name, @RequestParam(value="pwd") String pwd, Model model){ logger.info("enter userLogin..."); User user = userService.getUserByNameAndPassword(name, pwd); if(user == null){ logger.info("user is not exist..."); model.addAttribute("login_error", "User name or password error"); return "user/userLogin"; } SecurityUtils.setSecurityManager(sm); Subject currentUser = SecurityUtils.getSubject(); currentUser.getSession().setAttribute("LOGIN_USER", user); return "redirect:/employee/list"; }}Get the current user, in shiro, it is the theme, then get the corresponding session, and set the user information in it. Does it feel a bit like the operation of the Http session? Haha.
5) Finally, define a springmvc interceptor to obtain the user information in the corresponding session in the interceptor. If it cannot be obtained, it will jump to the login interface.
package com.smart.core.shiro;import com.smart.pojo.User;import org.apache.shiro.SecurityUtils;import org.apache.shiro.mgt.SecurityManager;import org.apache.shiro.subject.Subject;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class LoginInterceptor implements HandlerInterceptor { private Logger logger = LoggerFactory.getLogger(LoginInterceptor.class); @Autowired private SecurityManager sm; @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { logger.info("enter LoginInterceptor..."); HttpServletRequest request = httpServletRequest; HttpServletResponse response = httpServletResponse; logger.info("request uri===>"+request.getRequestURI()); //If it is a request for the login page, it will not be intercepted, otherwise it will fall into a dead loop if(request.getRequestURI().contains("loginPage") || request.getRequestURI().contains("userLogin")){ return true; }else{ SecurityUtils.setSecurityManager(sm); Subject currentUser = SecurityUtils.getSubject(); Object obj = currentUser.getSession().getAttribute("LOGIN_USER"); if(obj==null){ response.sendRedirect("http://localhost:8080/user/loginPage"); return false; }else{ User user = (User)obj; if(user==null || user.getName()==null){ response.sendRedirect("http://localhost:8080/user/loginPage"); return false; }else{ return true; } } } } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { }}It's basically over here. If you access the homepage information directly now, it will automatically jump to the login page.
Summarize
The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support to Wulin.com.