Shiro基础知识06----与Web集成(使用ini测试,使用数据库)

1、身份验证(登录)--使用ini配置文件

1.web.xm配置,并配置2个servlet

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         id="WebApp_ID" version="2.5">
    <display-name>shiro-base</display-name>

    <!-- 添加shiro支持,怎么配置可以参考官方文档 -->
    <!--从Shiro 1.2开始引入了Environment/WebEnvironment的概念,
    即由它们的实现提供相应的SecurityManager及其相应的依赖。ShiroFilter会自动找到Environment然后获取相应的依赖。
    通过EnvironmentLoaderListener来创建相应的WebEnvironment,并自动绑定到ServletContext,默认使用IniWebEnvironment实现。-->
    <listener>
        <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
    </listener>
    <filter>
        <filter-name>ShiroFilter</filter-name>
        <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>ShiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>


    <servlet>
        <servlet-name>loginServlet</servlet-name>
        <servlet-class>com.changwen.shiro.shiro_web.servlet.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>loginServlet</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>adminServlet</servlet-name>
        <servlet-class>com.changwen.shiro.shiro_web.servlet.AdminServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>adminServlet</servlet-name>
        <url-pattern>/admin</url-pattern>
    </servlet-mapping>
</web-app>
2.shiro.ini配置
ini配置部分和之前的相比将多出对url部分的配置。
[main]
authc.loginUrl=/login
roles.unauthorizedUrl=/unauthorized.jsp
perms.unauthorizedUrl=/unauthorized.jsp

[users]
tom=123,admin
jack=1234,teacher
marry=1235

[roles]
admin=user:*
teacher=student:*

[urls]
/login=anon
/admin=authc
/student=roles[teacher]
/teacher=perms["user:create"]
    其中最重要的就是[urls]部分的配置,其格式是: “url=拦截器[参数],拦截器[参数]”;即如果当前请求的url匹配[urls]部分的某个url模式,将会执行其配置的拦截器。比如anon拦截器表示匿名访问(即不需要登录即可访问);authc拦截器表示需要身份认证通过后才能访问;roles[admin]拦截器表示需要有admin角色授权才能访问;而perms["user:create"]拦截器表示需要有“user:create”权限才能访问。
---------------------------------------------------补充知识----------------------------------------------
url模式使用Ant风格模式
Ant路径通配符支持?、*、**,注意通配符匹配不包括目录分隔符“/”:
  ?:匹配一个字符,如”/admin?”将匹配/admin1,但不匹配/admin或/admin2;
  *:匹配零个或多个字符串,如/admin*将匹配/admin、/admin123,但不匹配/admin/1;
  **:匹配路径中的零个或多个路径,如/admin/**将匹配/admin/a或/admin/a/b。
url模式匹配顺序
  url模式匹配顺序是按照在配置中的声明顺序匹配,即从头开始使用第一个匹配的url模式对应的拦截器链。如:
    /bb/**=filter1  
    /bb/aa=filter2  
    /**=filter3   
如果请求的url是“/bb/aa”,因为按照声明顺序进行匹配,那么将使用filter1进行拦截。拦截器将在下一节详细介绍。
---------------------------------------------------------------------------------------------------------
3.servlet代码编写
public class AdminServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("admin do get");
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("admin do post");
	}
}
public class LoginServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("login doget");
		// 没有登陆的转发到login.jap
		req.getRequestDispatcher("login.jsp").forward(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("login dopost");
		String userName=req.getParameter("userName");
		String password=req.getParameter("password");
		Subject subject=SecurityUtils.getSubject();
<pre name="code" class="java">//UsernamePasswordToken token=new UsernamePasswordToken(userName, CryptographyUtil.md5(password,"test"));
 UsernamePasswordToken token=new UsernamePasswordToken(userName, password);try{subject.login(token);Session session=subject.getSession();System.out.println("sessionId:"+session.getId());System.out.println("sessionHost:"+session.getHost());System.out.println("sessionTimeout:"+session.getTimeout());session.setAttribute("info", "session的数据");resp.sendRedirect("success.jsp");}catch(Exception e){e.printStackTrace();req.setAttribute("errorInfo", "用户名或者密码错误");req.getRequestDispatcher("login.jsp").forward(req, resp);}}}
 4.jsp 

login.jsp核心代码
<form action="login" method="post">
	userName:<input type="text" name="userName"/><br/>
	password:<input type="password" name="password"/><br/>
	<input type="submit" value="登录"/>${errorInfo}
</form>
success.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!-- shiro jsp标签-->
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
欢迎你!
<!--hasRole标签:如果当前Subject有任意一个角色(或的关系)将显示body体内容。  -->
<shiro:hasRole name="admin">
    用户[<shiro:principal/>]拥有角色admin<br/>
</shiro:hasRole>
</body>
</html>
2、使用数据库配置

1、定义实体及关系


    即用户-角色之间是多对多关系,角色-权限之间是多对多关系;且用户和权限之间通过角色建立关系;在系统中验证时通过权限验证,角色只是权限集合,即所谓的显示角色;其实权限应该对应到资源(如菜单、URL、页面按钮、Java方法等)中,即应该将权限字符串存储到资源实体中,但是目前为了简单化,直接提取一个权限表,

// 角色表
DROP TABLE IF EXISTS t_role ;
CREATE TABLE t_role (
  id INT(11) NOT NULL AUTO_INCREMENT,
  roleName VARCHAR(20) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

INSERT  INTO t_role(id,roleName) VALUES (1,'admin'),(2,'teacher');

// 用户表
DROP TABLE IF EXISTS t_user;
CREATE TABLE t_user (
  id INT(11) NOT NULL AUTO_INCREMENT,
  userName VARCHAR(20) DEFAULT NULL,
  PASSWORD VARCHAR(100) DEFAULT NULL,
  roleId INT(11) DEFAULT NULL,
  PRIMARY KEY (id),
  KEY roleId (roleId),
  CONSTRAINT t_user_ibfk_1 FOREIGN KEY (roleId) REFERENCES t_role (id)
) ENGINE=INNODB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

INSERT  INTO t_user(id,userName,PASSWORD,roleId) 
VALUES (1,'tom','123',1),(2,'jack','1234',2),(3,'marry','1235',NULL);

// 权限表
CREATE TABLE t_permission (
  id INT(11) NOT NULL AUTO_INCREMENT,
  permissionName VARCHAR(50) DEFAULT NULL,
  roleId INT(11) DEFAULT NULL,
  PRIMARY KEY (id),
  KEY roleId (roleId),
  CONSTRAINT t_permission_ibfk_1 FOREIGN KEY (roleId) REFERENCES t_role (id)
) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

INSERT  INTO t_permission(id,permissionName,roleId) VALUES (1,'user:*',1),(2,'student:*',2);

2.自定义myReaml
// 自定义的reaml
public class MyRealm extends AuthorizingRealm{
	private UserDao userDao=new UserDao();
	private DbUtil dbUtil=new DbUtil();
	/**
	 * 先验证当前登录的用户
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		// 获取当前用户名
		String userName=(String)token.getPrincipal();
		Connection con=null;
		try{
			con=dbUtil.getCon();
			User user=userDao.getByUserName(con, userName);
			if(user!=null){
				AuthenticationInfo authcInfo=new SimpleAuthenticationInfo(user.getUserName(),user.getPassword(),"xx");
				return authcInfo;
			}else{
				return null;
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			try {
				dbUtil.closeCon(con);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	/**
	 * 为当前登录的用户授予角色和权限
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		String userName=(String)principals.getPrimaryPrincipal();
		SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
		Connection con=null;
		try{
			con=dbUtil.getCon();
			authorizationInfo.setRoles(userDao.getRoles(con,userName));
			authorizationInfo.setStringPermissions(userDao.getPermissions(con,userName));
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			try {
				dbUtil.closeCon(con);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return authorizationInfo;
	}

}
Userdao
public class UserDao {

	public User getByUserName(Connection con,String userName)throws Exception{
		User resultUser=null;
		String sql="select * from t_user where userName=?";
		PreparedStatement pstmt=con.prepareStatement(sql);
		pstmt.setString(1, userName);
		ResultSet rs=pstmt.executeQuery();
		if(rs.next()){
			resultUser=new User();
			resultUser.setId(rs.getInt("id"));
			resultUser.setUserName(rs.getString("userName"));
			resultUser.setPassword(rs.getString("password"));
		}
		return resultUser;
	}

	public Set<String> getRoles(Connection con, String userName) throws Exception{
		Set<String> roles=new HashSet<String>();
		String sql="select * from t_user u,t_role r where u.roleId=r.id and u.userName=?";
		PreparedStatement pstmt=con.prepareStatement(sql);
		pstmt.setString(1, userName);
		ResultSet rs=pstmt.executeQuery();
		while(rs.next()){
			roles.add(rs.getString("roleName"));
		}
		return roles;
	}

	public Set<String> getPermissions(Connection con, String userName)throws Exception {
		Set<String> permissions=new HashSet<String>();
		String sql="select * from t_user u,t_role r,t_permission p where u.roleId=r.id and p.roleId=r.id and u.userName=?";
		PreparedStatement pstmt=con.prepareStatement(sql);
		pstmt.setString(1, userName);
		ResultSet rs=pstmt.executeQuery();
		while(rs.next()){
			permissions.add(rs.getString("permissionName"));
		}
		return permissions;
	}
}
实例类User
public class User {
	private Integer id;
	private String userName;
	private String password;
	
//省去get,set方法
}
shiro.ini配置文件
[main]
authc.loginUrl=/login
roles.unauthorizedUrl=/unauthorized.jsp
perms.unauthorizedUrl=/unauthorized.jsp

#[users]
#tom=123,admin
#jack=1234,teacher
#marry=1235
#[roles]
#admin=user:*
#teacher=student:*
# 使用数据库测试替换上面
myRealm=com.changwen.shiro.shiro_web.realm.MyRealm
securityManager.realms=$myRealm

[urls]
/login=anon
/admin=authc
/student=roles[teacher]
/teacher=perms["user:create"]

--------------------------------------------------------------------------------------------

两个工具类

/**
 * 数据库工具类
 */
public class DbUtil {

	/**
	 * 获取数据库连接
	 */
	public Connection getCon() throws Exception{
		Class.forName("com.mysql.jdbc.Driver");
		Connection con=DriverManager.getConnection("jdbc:mysql://localhost:3306/db_shiro", "root", "123456");

//		Class.forName("oracle.jdbc.OracleDriver");
//		Connection con=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "root", "123456");
		return con;
	}

	/**
	 * 关闭数据库连接
	 */
	public void closeCon(Connection con)throws Exception{
		if(con!=null){
			con.close();
		}
	}
   // 测试
	public static void main(String[] args) {
		DbUtil dbUtil=new DbUtil();
		try {
			dbUtil.getCon();
			System.out.println("数据库连接成功");
			
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("数据库连接失败");
		}
	}
}
public class CryptographyUtil {

	/**
	 * base64加密
	 */
	public static String encBase64(String str){
		return Base64.encodeToString(str.getBytes());
	}

	/**
	 * base64解密
	 */
	public static String decBase64(String str){
		return Base64.decodeToString(str);
	}

	/**
	 * Md5加密,不能解密
	 * @param salt 盐值
	 */
	public static String md5(String str,String salt){
		return new Md5Hash(str,salt).toString();
	}

	public static void main(String[] args) {
		String password="123456";
		System.out.println("Base64加密:"+CryptographyUtil.encBase64(password));
		System.out.println("Base64解密:"+CryptographyUtil.decBase64(CryptographyUtil.encBase64(password)));

		System.out.println("Md5加密:"+CryptographyUtil.md5(password, "123456"));
	}
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值