redis实现单点登录系统
<groupId>cn.e3mall</groupId>
<artifactId>e3-sso</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>e3-sso-interface</module>
<module>e3-sso-service</module>
</modules>
<dependencies>
<dependency>
<groupId>cn.e3mall</groupId>
<artifactId>e3-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<!-- 配置tomcat插件 -->
<build>
<plugins>
<plugin>
<!-- 配置Tomcat插件 -->
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<path>/</path><!-- 表示访问时候不带工程名的 -->
<port>8087</port>
</configuration>
</plugin>
</plugins>
</build>
<parent>
<groupId>cn.e3mall</groupId>
<artifactId>e3-sso</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>e3-sso-interface</artifactId>
<dependencies>
<dependency>
<groupId>cn.e3mall</groupId>
<artifactId>e3-manager-pojo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<parent>
<groupId>cn.e3mall</groupId>
<artifactId>e3-sso</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>e3-sso-service</artifactId>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>cn.e3mall</groupId>
<artifactId>e3-manager-dao</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.e3mall</groupId>
<artifactId>e3-sso-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- dubbo相关 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>org.jboss.netty</groupId>
<artifactId>netty</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
</dependency>
</dependencies>
<!-- 数据库连接池 -->
<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:conf/*.properties" />
<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="driverClassName" value="${jdbc.driver}" />
<property name="maxActive" value="10" />
<property name="minIdle" value="5" />
</bean>
<!-- 让spring管理sqlsessionfactory 使用mybatis和spring整合包中的 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 数据库连接池 -->
<property name="dataSource" ref="dataSource" />
<!-- 加载mybatis的全局配置文件 -->
<property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.e3mall.mapper" />
</bean>
<!-- 事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 传播行为 -->
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="create*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
<tx:method name="select*" propagation="SUPPORTS" read-only="true" />
<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- 切面 -->
<aop:config>
<aop:advisor advice-ref="txAdvice"
pointcut="execution(* cn.e3mall.sso.service..*.*(..))" />
</aop:config>
<!-- 连接redis单机版 -->
<bean id="jedisClientPool" class="cn.e3mall.common.jedis.JedisClientPool">
<property name="jedisPool" ref="jedisPool"></property>
</bean>
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<!-- 一定要用name,构造方法太多用index容易错 -->
<constructor-arg name="host" value="192.168.25.128"/>
<constructor-arg name="port" value="6379"/>
</bean>
<!-- 加载spring容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/e3mall_32?characterEncoding=utf-8
jdbc.username=root
jdbc.password=123456
SESSION_EXPIRE=1800
<groupId>cn.e3mall</groupId>
<artifactId>e3-sso-web</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>cn.e3mall</groupId>
<artifactId>e3-sso-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- JSP相关 -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- dubbo相关 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>org.jboss.netty</groupId>
<artifactId>netty</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
</dependency>
</dependencies>
<!-- 配置tomcat插件 -->
<build>
<plugins>
<plugin>
<!-- 配置Tomcat插件 -->
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<path>/</path><!-- 表示访问时候不带工程名的 -->
<port>8088</port>
</configuration>
</plugin>
</plugins>
</build>
<!-- 解决post乱码 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- springmvc的前端控制器 -->
<servlet>
<servlet-name>e3-manager</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- contextConfigLocation不是必须的, 如果不配置contextConfigLocation, springmvc的配置文件默认在:WEB-INF/servlet的name+"-servlet.xml" -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>e3-manager</servlet-name>
<!-- 伪静态化,搜索引擎优化,搜索引擎会先找静态页面 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
TOKEN_KEY=token
/*
* 用户登录处理
*/
@Service
public class LoginServiceImpl implements LoginService{
@Autowired
private TbUserMapper userMapper;
@Autowired
private JedisClient jedisClient;
@Value("${SESSION_EXPIRE}")
private Integer SESSION_EXPIRE;
public E3Result userLogin(String username, String password) {
//1.判断用户名和密码是否正确
//根据用户名查询用户信息
TbUserExample example = new TbUserExample();
Criteria criteria = example.createCriteria();
criteria.andUsernameEqualTo(username);
List<TbUser> list = userMapper.selectByExample(example);
if(list == null || list.size() == 0){
//返回登录失败
return E3Result.build(400, "用户名或者密码错误");
}
//取用户信息
TbUser user = list.get(0);
//判断密码是否正确
if(!DigestUtils.md5DigestAsHex(password.getBytes()).equals(user.getPassword())){
//2.如果不正确返回登录失败
return E3Result.build(400, "用户名或者密码错误");
}
//3.如果正确生成token
String token = UUID.randomUUID().toString();//生成的uuid必不重复
//4.把用户信息写入redis,key:token,value:用户信息
user.setPassword(null);
jedisClient.set("SESSION:"+ token, JsonUtils.objectToJson(user));
//5.设置Session的过期时间
jedisClient.expire("SESSION:"+ token, SESSION_EXPIRE);
//6.把token返回
return E3Result.ok(token);
}
}
public class E3Result implements Serializable{
// 定义jackson对象
private static final ObjectMapper MAPPER = new ObjectMapper();
// 响应业务状态
private Integer status;
// 响应消息
private String msg;
// 响应中的数据
private Object data;
public static E3Result build(Integer status, String msg, Object data) {
return new E3Result(status, msg, data);
}
public static E3Result ok(Object data) {
return new E3Result(data);
}
public static E3Result ok() {
return new E3Result(null);
}
public E3Result() {
}
public static E3Result build(Integer status, String msg) {
return new E3Result(status, msg, null);
}
public E3Result(Integer status, String msg, Object data) {
this.status = status;
this.msg = msg;
this.data = data;
}
public E3Result(Object data) {
this.status = 200;
this.msg = "OK";
this.data = data;
}
get、set方法
}
<context:component-scan base-package="cn.e3mall.sso.service"/>
<!-- 使用dubbo发布服务 -->
<!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="e3-sso" />
<dubbo:registry protocol="zookeeper"
address="192.168.25.128:2181" />
<!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20883" /><!-- 一个服务对应一个端口 -->
<!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="cn.e3mall.sso.service.LoginService"
ref="loginServiceImpl" timeout="600000"/>
<dubbo:service>
<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:conf/resource.properties" />
<context:component-scan base-package="cn.e3mall.sso.controller" />
<mvc:annotation-driven />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/js/" mapping="/js/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>
<!-- 引用dubbo服务 -->
<dubbo:application name="e3-sso-web"/>
<dubbo:registry protocol="zookeeper" address="192.168.25.128:2181"/>
<dubbo:reference interface="cn.e3mall.sso.service.LoginService" id="loginService" />
/*
* 用户登录处理
*/
@Controller
public class LoginController {
@Autowired
private LoginService loginService;
@Value("${TOKEN_KEY}")
private String TOKEN_KEY;//TOKEN_KEY=token
@RequestMapping("/page/login")
public String toLogin(String redirect,Model model){
model.addAttribute("redirect", redirect);
//返回登录页面
return "login";
}
@RequestMapping(value="/user/login",method=RequestMethod.POST)
@ResponseBody
public E3Result login(String username,String password,
HttpServletRequest request,HttpServletResponse response){
E3Result result = loginService.userLogin(username, password);
//判断是否登录成功
if(result.getStatus()==200){
String token = (String) result.getData();
//如果登录成功,token写入cookie
CookieUtils.setCookie(request, response, TOKEN_KEY, token);
}
return result;
}
}
private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
String cookieName, String cookieValue, int cookieMaxage, boolean isEncode) {
try {
if (cookieValue == null) {
cookieValue = "";
} else if (isEncode) {
cookieValue = URLEncoder.encode(cookieValue, "utf-8");
}
Cookie cookie = new Cookie(cookieName, cookieValue);
if (cookieMaxage > 0)
cookie.setMaxAge(cookieMaxage);
if (null != request) {// 设置域名的cookie
String domainName = getDomainName(request);
System.out.println(domainName);
if (!"localhost".equals(domainName)) {
cookie.setDomain(domainName);
}
}
cookie.setPath("/");
response.addCookie(cookie);
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* 用户登录处理
*/
public class LoginInterceptor implements HandlerInterceptor {
@Autowired
private TokenService tokenService;
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//前处理,执行handler之前执行此方法
//返回true:放行 false:拦截
//1.从cookie中取token
String token = CookieUtils.getCookieValue(request, "token");
//2.如果没有token,未登录状态
if(StringUtils.isBlank(token)){
return true;
}
//3.如果取到token,需要调用sso系统的服务,根据token取用户信息
E3Result e3Result = tokenService.getUserByToken(token);
if (e3Result.getStatus()!=200){
//4.没有取到用户信息,登录已经过期,直接放行
return true;
}
//5.取到用户信息。登录状态。
TbUser user = (TbUser) e3Result.getData();
//6.把用户信息放到request中,只需要在controller中判断request中是否包含user信息。
request.setAttribute("user", user);
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
//handler执行之后,返回modelAndView之前
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
//完成处理,返回modelAndView之后(已经响应了)
//可以再次处理异常
}
}
<dubbo:service interface="cn.e3mall.sso.service.TokenService"
ref="tokenServiceImpl" timeout="600000"/>
/*
* 根据token取用户信息
*/
@Service
public class TokenServiceImpl implements TokenService{
@Autowired
private JedisClient jedisClient;
@Value("${SESSION_EXPIRE}")
private Integer SESSION_EXPIRE;
public E3Result getUserByToken(String token) {
//根据token到redis中取用户信息
String json = jedisClient.get("SESSION:"+ token);
if(StringUtils.isBlank(json)){
//取不到信息,登录过期,返回登录过期
return E3Result.build(201, "用户登录已经过期");
}
//取到用户信息,跟新token的过期时间
jedisClient.expire("SESSION:"+ token, SESSION_EXPIRE);
//返回结果,E3Result其中包含用户对象
TbUser user = JsonUtils.jsonToPojo(json, TbUser.class);
return E3Result.ok(user);
}
}
<dubbo:reference interface="cn.e3mall.sso.service.TokenService" id="tokenService" />
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:
https://blog.csdn.net/qq_37334135/article/details/77727456
— 【 THE END 】— 本公众号全部博文已整理成一个目录,请在公众号里回复「m」获取! 最近面试BAT,整理一份面试资料《Java面试BATJ通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。
获取方式:点“在看”,关注公众号并回复 PDF 领取,更多内容陆续奉上。
文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
评论