项目结构
注意事项
图片如果没有显示,注意放行静态资源,在LinkedHashMap让图片资源匿名访问
<!--放行静态资源 -->
<mvc:default-servlet-handler/>
map.put("/images/**", "anon");
可以运行UserRealm里面的main方法来生成你需要的密码
public static void main(String[] args) {
String hashAlgorithmName="MD5";
Object credentials="1234";
//Object salt= ByteSource.Util.bytes("admin");
//Object salt= ByteSource.Util.bytes("user");
Object salt= ByteSource.Util.bytes("test");
int hashIterations=1;
Object result=new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
System.out.println(result);
//admin-1234-c93ccd78b2076528346216b3b2f701e6
//user-1234-b5b73fae0d87d8b4e2573105f8fbe7bc
//test-1234-16d7a4fca7442dda3ad93c9a726597e4
}
UserRealm
package com.shiro.realm;
import java.util.HashSet;
import java.util.Set;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
public class UserRealm extends AuthorizingRealm{
//用于认证的方法
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("doGetAuthenticationInfo:"+token);
//1.把AuthenticationToken转换为UsernamePasswordToken
UsernamePasswordToken upToken=(UsernamePasswordToken) token;
//2.从UsernamePasswordToken获取username
String username=upToken.getUsername();
//3.调用数据库的方法,从数据库中查询username中对应的用户记录
System.out.println("获取username "+username+" 的信息");
//4.若用户不存在,则抛出UnknownAccountException异常
if("unknown".equals(username)){
throw new UnknownAccountException("用户不存在");
}
//5.根据用户信息,决定是否需要抛出其他的AuthenticationException异常
if("monster".equals(username)){
throw new LockedAccountException("用户被锁定");
}
//6.根于用户的情况,来构建Authenication对象并返回
String realmName=getName();
//以下信息应从数据库获取
Object principal=username;
Object hashedCredentials=null;
if("admin".equals(username)){
hashedCredentials="c93ccd78b2076528346216b3b2f701e6";
}else if("test".equals(username)){
hashedCredentials="16d7a4fca7442dda3ad93c9a726597e4";
}else if("user".equals(username)){
hashedCredentials="b5b73fae0d87d8b4e2573105f8fbe7bc";
}
//盐值
ByteSource credentialsSalt = ByteSource.Util.bytes(username);
System.out.println("realmName "+realmName);
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(principal, hashedCredentials, credentialsSalt, realmName);
return info;
}
//用于授权的方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("doGetAuthorizationInfo...");
//1.PrincipalCollection获取登录用户的信息
Object principal=principals.getPrimaryPrincipal();
//2.利用登录的用户信息来获取当前用户的角色或权限
Set<String> roles=new HashSet<>();
roles.add("test");
if("user".equals(principal)){
roles.add("user");
}else if("admin".equals(principal)){
roles.add("user");
roles.add("admin");
}
//3.创建SimpleAuthorizationInfo,并设置其roles属性
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo(roles);
//4.返回SimpleAuthorizationInfo对象
return info;
}
public static void main(String[] args) {
String hashAlgorithmName="MD5";
Object credentials="1234";
//Object salt= ByteSource.Util.bytes("admin");
//Object salt= ByteSource.Util.bytes("user");
Object salt= ByteSource.Util.bytes("test");
int hashIterations=1;
Object result=new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
System.out.println(result);
//admin-1234-c93ccd78b2076528346216b3b2f701e6
//user-1234-b5b73fae0d87d8b4e2573105f8fbe7bc
//test-1234-16d7a4fca7442dda3ad93c9a726597e4
}
}
FilterChainDefinitionMapBuilder
package com.shiro.factroy;
import java.util.LinkedHashMap;
public class FilterChainDefinitionMapBuilder {
public LinkedHashMap<String, String> buildFilterChainDefinitionMap(){
LinkedHashMap<String, String> map=new LinkedHashMap<>();
/**
*
<entry key="/login.jsp" value="anon"/>
<entry key="/user/userLogin" value="anon"/>
<entry key="/user/logout" value="logout"/>
<entry key="/user.jsp" value="roles[user]"/>
<entry key="/admin.jsp" value="roles[admin]"/>
<entry key="/test.jsp" value="roles[test]"/>
<entry key="/**" value="authc"/>
*/
map.put("/login.jsp", "anon");
map.put("/images/**", "anon");
map.put("/user/userLogin", "anon");
map.put("/user/logout", "logout");
map.put("/user.jsp", "roles[user]");
map.put("/admin.jsp", "roles[admin]");
map.put("/test.jsp", "roles[test]");
map.put("/**", "authc");
return map;
}
}
UserController
package com.shiro.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/userLogin")
public String login(@RequestParam("username")String username,@RequestParam("password")String password){
Subject currentUser=SecurityUtils.getSubject();
if(!currentUser.isAuthenticated()){
UsernamePasswordToken token=new UsernamePasswordToken(username,password);
token.setRememberMe(true);
try {
currentUser.login(token);
} catch (AuthenticationException e) {
System.out.println("登录失败: "+e.getMessage());
}
}
return "redirect:/list.jsp";
}
}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ssttisme</groupId>
<artifactId>shiro-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<!-- 整合shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!-- 整合ehcache -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
web.xml
<?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"
version="2.5">
<display-name>shiro-demo</display-name>
<welcome-file-list>
<welcome-file>user.jsp</welcome-file>
</welcome-file-list>
<!--配置SpringMVC前端控制器 -->
<!--注册前端控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--初始化参数读取配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<!--配置servlet在服务启动时加载(数字越小,优先级越高) 配置如下选项以后,tomcat启动时会初始化这个servlet 这个servlet在初始化时会读取contextConfigLocation参数对应的配置文件。 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!--配置前端控制器 -->
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 配置shiroFilter -->
<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>
</web-app>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.3.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<import resource="classpath:applicationContext-mvc.xml"/>
<import resource="classpath:applicationContext-shiro.xml"/>
</beans>
applicationContext-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.3.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 自动扫描包 -->
<context:component-scan base-package="com.shiro" />
<!-- 启用mvc注解 -->
<mvc:annotation-driven />
<!--放行静态资源 -->
<mvc:default-servlet-handler/>
<!--配置springMVC视图解析器(负责视图解析操作) -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前缀 -->
<property name="Prefix" value="/"></property>
<property name="Suffix" value=".jsp"></property>
</bean>
</beans>
applicationContext-shiro.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.3.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 配置Shiro中的SecurityManager -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="shiroUserRealm"></property>
<!--设置shiro记住我 -->
<property name="rememberMeManager.cookie.maxAge" value="5"/>
</bean>
<!-- 配置realm
实现了org.apache.shiro.realm.Realm接口的bean-->
<bean id="shiroUserRealm" class="com.shiro.realm.UserRealm">
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="MD5"/>
<property name="hashIterations" value="1"/>
</bean>
</property>
</bean>
<!-- 配置Shiro的ShiroFilterFactoryBean对象
必须与web.xml中配置的DelegatingFilterProxy的<filter-name>一致
-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="SecurityManager" ref="securityManager">
</property>
<!--设置此项的目的是让用户先进行登录认证 -->
<property name="loginUrl" value="/login.jsp"/>
<property name="successUrl" value="/list.jsp"/>
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
<!--设置请求过滤规则
配置哪些页面需要受保护,以及访问这些页面需要的权限-->
<property name="FilterChainDefinitionMap" ref="filterChainDefinitionMap"/>
</bean>
<!-- 配置一个bean,该bean实际上是一个map,通过实例工厂的方式 -->
<bean id="filterChainDefinitionMap" factory-bean="filterChainDefinitionMapBuilder" factory-method="buildFilterChainDefinitionMap"></bean>
<bean id="filterChainDefinitionMapBuilder" class="com.shiro.factroy.FilterChainDefinitionMapBuilder"/>
<!-- 授权 -->
<!-- 配置bean对象的生命周期管理 (可以自动地调用配置在springIoc容器中shiro-bean的生命周期方法)-->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor">
</bean>
<!-- 配置bean对象的代理 -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor">
</bean>
<!-- 配置授权属性 -->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="SecurityManager" ref="securityManager"></property>
</bean>
</beans>
admin.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>用户中心</title>
<style type="text/css">
textarea {
resize: none;
}
</style>
</head>
<body>
<h2>用户列表-表单就是专门用来收集用户信息的</h2>
<form>
<fieldset>
<legend>查询条件</legend>
<label for="keyword">关键字:</label> <input type="text" id="keyword"
list="keywordlist" />
<datalist id="keywordlist">
<option>张三</option>
<option>李四</option>
<option>王五</option>
<option>妈宝男</option>
<option>帅哥</option>
</datalist>
<!-- html中如果属性的取值和属性的名称一样,可以只写一个 。在xhtml中必须写上取值-->
性别:男<input type="radio" name="sex" checked="checked" value="male" />女<input
type="radio" name="sex" value="female" /> 条件:未婚<input
type="checkbox" /> 富有<input type="checkbox" checked /> 高学历<input
type="checkbox" /> <br> <br> <input type="button" value="查询" title="点击查询" /> <input type="reset"> <br>
</fieldset>
<fieldset>
<legend>个性调查</legend>
<br> 邮箱:<input type="email"> 喜欢的颜色:<input type="color"
name="color" />
<br> <br>
电话号码:<input type="number"> <br> <br>
出生日期:<input type="date"> <br> <br> 爱好: <select>
<option>文科</option>
<option selected="selected">理科</option>
</select>
所在地:
<select name="address">
<optgroup label="北京">
<option>朝阳</option>
<option>昌平</option>
<option>通州</option>
</optgroup>
<optgroup label="广州">
<option>越秀</option>
<option>海珠</option>
<option>天河</option>
</optgroup>
</select> <br> <br>
简介:<textarea rows="10" cols="80" name="desc"></textarea>
</fieldset>
<br> <a href="list.jsp">返回</a>
<input type="submit">
</form>
</body>
</html>
list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>列表</title>
<base target="_self">
<style type="text/css">
* {
margin: 0;
padding: 0;
}
h2 {
color: white;
}
ul {
list-style-type: none;
width: 250px;
margin-top: 50px;
background-color: aqua;
text-align: center;
}
ul li {
width: 100%;
height: 50px;
lint-height: 50px;
background-color: #da2eb8;
}
ul li:hover {
background-color: #44f278;
}
ul li a {
display: block;
width: 100%;
height: 50px;
line-height: 50px;
text-decoration: none;
}
body {
background: url("images/gtr.jpg") no-repeat center;
}
</style>
</head>
<body>
<h2>我的权限管理系统</h2>
<ul>
<li><a href="admin.jsp">admin菜单</a></li>
<li><a href="user.jsp">user菜单</a></li>
<li><a href="test.jsp">test菜单</a></li>
<li><a href="user/logout" title="即将注销">注销</a></li>
</ul>
</body>
</html>
login.jsp-登录页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>登录</title>
<style type="text/css">
body{
background: url("images/gtr.jpg") no-repeat center ;
}
h2,label{
color:white;
}
.loginBox{
text-align:center;
width:550px;
height:400px;
margin:100px auto;
border:solid 1px pink;
background-color:#44000018;
padding-top:25px;
}
</style>
</head>
<body>
<div class="loginBox">
<h2>登录</h2>
<form action="user/userLogin" method="post">
<label for="username">用户名:</label><input type="text" name="username" id="username">
<br><br>
<label for="password">密 码:</label><input type="password" name="password" id="password">
<br><br>
<input type="submit" value="登录">
<input type="reset" value="清空">
</form>
</div>
</body>
</html>
test.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>用户中心</title>
<body>
<h4>测试列表</h4>
<h5>查看-测试信息</h5>
<ol type="i">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
<li>11</li>
</ol>
<a href="list.jsp">返回</a>
</body>
</html>
unauthorized.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>警告</title>
<style type="text/css">
h3{color:red;}
</style>
</head>
<body>
<h3>您无权访问本页面!</h3>
<a href="list.jsp">返回</a>
</body>
</html>
user.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>用户中心</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
body, html {
width: 100%;
height: 100%;
}
h4 {
width: 100%;
background: cyan;
}
ul {
list-style-type: none;
width: 100%;
height: 50px;
line-height: 50px;
}
li {
float: left;
background-color: pink;
text-align: center;
width: 25%;
height: 100%;
}
li:hover {
background-color: yellow;
}
</style>
<body>
<h4>用户列表</h4>
<ul>
<li>个人信息</li>
<li>修改密码</li>
<li>积分查看</li>
<li><input type="image" src="images/undo.png" onclick="logout()" /></li>
</ul>
<table width="250px" border="1" cellpadding="0" cellspacing="0">
<tr>
<td>姓名</td><td>张三</td>
<td>账号余额</td><td>300</td>
</tr>
<tr>
<td>性别</td><td>男</td>
<td>利息</td><td>5</td>
</tr>
</table>
<script>
function logout() {
location.href = "user/logout";
}
</script>
</body>
</html>