测试开发系列之——用户登录功能

方法调用逻辑

  1. shiro config
  2. subject.login-securityManager.setRealm(myReal);-new MyRealm();
  3. 回调doGetAuthorizationInfo,返回doGetAuthorizationInfo
  4. 将dbUser(用户信息)放入session,同时sessionId自动生成。shiro会帮忙维护一个session,与tomcat的session不同,是独立的一套机制,仿照tomcat的那种,与tomcat容器没有关系。java的工程也可以用shiro做会话管理,与web容器没有关系,是独立的。
    前面几步都是做认证,最后一步是做会话管理。
    在这里插入图片描述

Spring的原理

  • tomcat启动的时候,有一个监听器listener – 上下文监听器servletContextListener
  • spring容器何时启动的呢?就是这个上下文监听器监听到创建上下文,就开始启动spring
  • 启动了spring,接下来要做的事情就是spring初始化,加载配置文件,只不过现在把配置文件淘汰掉了,变成配置类了

shiro认证

Shiro 中的 SecurityUtils(转),可参阅:
https://www.cnblogs.com/muxi0407/p/11987661.html

Subject subject = SecurityUtils.getSubject();
subject.login(token);
String sessionId = (String)subject.getSession().getId();

SecurityUtils.getSubject().logout();

SimpleAuthenticationInfo(dbUser,dbUser.getPassword(),getName());

MyRealm的代码

在com.one.shiro下创建类MyRealm.java

package com.one.shiro;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.one.pojo.User;
import com.one.service.UserService;

public class MyRealm extends AuthorizingRealm{
	@Autowired
	UserService userService;
	//授权(权限管理)
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
		// TODO Auto-generated method stub
		return null;
	}
	//身份认证
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		// 认证逻辑
		String username = token.getPrincipal().toString();
		
		QueryWrapper<User> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("username", username);
		User dbUser = userService.getOne(queryWrapper);
		
		if(dbUser!=null){
			/*if(dbUser.getPassword().equals(token.getCredentials())){

			}*/
			return new SimpleAuthenticationInfo(dbUser,dbUser.getPassword(),getName());
		}
		return null;
	}
}

ShiroConfig.java的代码

package com.one.shiro;

import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**shiro的配置
 * @author chenxia
 *
 */
@Configuration
public class ShiroConfig {
	@Bean
	public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {

		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		// 拦截器.
		Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
		// 配置不会被拦截的链接 顺序判断
		
		filterChainDefinitionMap.put("/user/login", "anon");
		filterChainDefinitionMap.put("/user/find", "anon");
		filterChainDefinitionMap.put("/user/register", "anon");

		// 过滤链定义,从上向下顺序执行
		// authc:url都必须认证通过才可以访问; anon:url都可以匿名访问
		filterChainDefinitionMap.put("/**", "authc");
	
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		// 如果不设置默认会自动寻找Web工程根目录下的"/login"页面
		shiroFilterFactoryBean.setLoginUrl("/user/unauth");
		return shiroFilterFactoryBean;
	}

	// 重新设置SecurityManager,通过自动以的MyRealm完成登录校验:
	@Bean
	public MyRealm myReal() {
		return new MyRealm();
	}

	@Bean
	public SecurityManager securityManager(MyRealm myReal) {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		 //自定义session管理
       // securityManager.setSessionManager(sessionManager());
		// 设置realm
		securityManager.setRealm(myReal);
		return securityManager;
	}

	/*@Bean
	public SessionManager sessionManager(){
		CustomSessionManager manager = new CustomSessionManager();
	        manager.setSessionDAO(new EnterpriseCacheSessionDAO());
		return manager;
	}*/
}

登录方法的编码

对com.one.controller中
UserController.java进行修改

	//登录
	@PostMapping("/login")
	@ApiOperation(value="登录方法", httpMethod="POST")
	public Result login(User user){
		Result result = null;
		try {
			UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(),user.getPassword());
			//shiro
			Subject subject = SecurityUtils.getSubject();
			subject.login(token);
			result = new Result("1","登录成功");
		} catch (AuthenticationException e) {
			if(e instanceof UnknownAccountException){
				result = new Result("0","用户名错误");
			}else{
				result = new Result("0","密码错误");
			}
			e.printStackTrace();
		}
		return result;
	}	

加入sessionId

对com.one.controller中
UserController.java进行修改,加入sessionId相关代码

			//将sessionId返回去
			String sessionId = (String) SecurityUtils.getSubject().getSession().getId();
			result = new Result("1",sessionId,"登录成功");

Result.java的编码

对com.one.common中
Result.java进行修改,新增构造方法
右键->Source->Generate Constructor using Fields…
在这里插入图片描述
同时要传3个参数
在这里插入图片描述
后端服务器写回的Cookie:
在这里插入图片描述
前端服务器的域名,在前端写到浏览器的Cookie里面。
因为域名不同,隔了一层,第二次请求时,自行携带sessionId,是前端服务器发异步请求的时候带过去。
带sessionId有两种方式,一种是请求头header里面带过去,一种是请求体body里面带过去。一般放在请求头header里面带过去。
在这里插入图片描述

前端login.html的代码

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>接口测试平台</title>
<link rel="stylesheet" type="text/css" href="/lemon/css/style.css" />
<style>
body {
	height: 100%;
	background: #16a085;
	overflow: hidden;
}

canvas {
	z-index: -1;
	position: absolute;
}
.tips{ font-size:12px; height:30px; clear:both;color:red}
.tips_dd_init{
	display:none;
}
</style>
<script src="/lemon/js/jquery-1.11.3.js"></script>
<script src="/lemon/js/Particleground.js"></script>
<script type="text/javascript" src="/lemon/js/jquery.md5.js" charset="UTF-8"></script>
<script type="text/javascript" src="/lemon/js/common.js" charset="UTF-8"></script>
<script type="text/javascript" src="/lemon/js/jquery.cookie.js" charset="UTF-8"></script>
<script>
	$(function() {
		//粒子背景特效
		$('body').particleground({
			dotColor : '#5cbdaa',
			lineColor : '#5cbdaa'
		});
		$("body").keydown(function(event) {
			if (event.keyCode == "13") {//keyCode=13是回车键
				$('#login').trigger("click");
			}
		});
		$("#login").click(
				function() {
					var un = $("[name='username']").val();
					var pd = $("[name='password']").val();
					if(un==null||un==""){
						$(".tips_dd_init").show();
						$("p.tips").html("用户名不能为空。");
						return false; 
					}  
					if(pd==null||pd==""){
						$(".tips_dd_init").show();
						$("p.tips").html("密码不能为空。");
						return false;
					}
					$(".tips_dd_init").hide();
					$.post(lemon.config.global.adminUrl + "/user/login", {
						username : un,
						password : $.md5(pd)
					}, function(ret) {
						if (ret != null && ret.status == "1") {
							var date = new Date();
							date.setTime(date.getTime() + 24 * 60 * 60
									* 1000);//1天
							//将后端的sessionId写入cookie
							$.cookie("sessionId", ret.data, {
								expires : date
							});
							window.location.href = lemon.config.global.rootUrl
									+ "/html/projectList.html";
						} else {
							$(".tips_dd_init").show();
							$("p.tips").html(ret.message);
						}
					}, 'json');

				});
	});
</script>
</head>
<body>
	<form name='loginForm'>
		<dl class="admin_login">
			<dt>
				<strong>接口测试平台</strong> <em>Management System</em>
			</dt>
			<dd class="user_icon">
				<input type="text" placeholder="账号" class="login_txtbx"
					name="username" />
			</dd>
			<dd class="pwd_icon">
				<input type="password" placeholder="密码" class="login_txtbx"
					name="password" />
			</dd>
			<dd class="tips_dd_init">
				<p class="tips" style="color:red"></p>
			</dd>
			<dd>
				<input type="button" value="立即登录" class="submit_btn" id="login"/>
			</dd>
			<dd>
				<p>
					还没账号?<a href="register.html" style="text-decoration: underline;"><strong>去注册</strong></a>
				</p>
			</dd>
		</dl>
	</form>
</body>
</html>

发布了27 篇原创文章 · 获赞 1 · 访问量 1659

猜你喜欢

转载自blog.csdn.net/anniewhite/article/details/104414043