java:shiro(认证,赋予角色,授权...)
1.shiro(权限框架(认证,赋予角色,授权...)):
readme.txt(运行机制):
1.从jsp的form中的action属性跳转到springmvc的Handler中(controller)
2.首先获取Subject,因为securityManager在applicationContext.xml中配置过了,所以可以直接
通过Subject currentUser = SecurityUtils.getSubject();
3.开始认证
首先把账号和密码封装进UsernamePasswordToken中,然后调用subject的login(UsernamePasswordToken);
4.真正的认证开始(需要和数据库进行交互)
select * from table where username="zhangsan"
select * from table where username="zhangsan" and passowrd="123456"
4.1 通过username先查询该登录用户是否存在,如果不存在就抛出异常
4.2 如果登录用户存在,再次检验是否可以正常使用,如果不能正常使用就抛出异常
4.3 匹配密码
5.密码匹配流程
5.1.从前端获取用户输入的密码
5.2.从数据库中通过用户名查询密码
5.3.把查询出的密码SimpleAuthenticationInfo
5.4.shiro会通过SimpleCredentialsMatcher.class中doCredentialsMatch()进行匹配从前端传递的密码和从数据库中查询的密码是否一致
5.4.1.doCredentialsMatch()会重写equals()来进行匹配if("123456".equals(user.getPassword()))
5.4.2.该方法中需要两个参数
AuthenticationToken(I)-实现类->UsernamePasswordToken(封装了前端传递的用户名和密码)
用户名和密码
AuthenticationInfo(I)-被继承->SaltedAuthenticationInfo(I)-实现类->SimpleAuthenticationInfo(username, user.getPassword(), getName())
username:获取密码使用
user.getPassword():需要和前端进行匹配
getName()-->realmName(ShiroRealm2)
为授权做准备
6.密码加密
6.1.因为密码为明文,存入数据库中和项目运行过程中会在开发者工具中出现,所以存在安全隐患问题(如果用户密码遭遇泄漏,并且牵扯到金钱问题,发开公司将会承担用户的一切损失)
6.2.进行为密码的加密
shiro会在配置文件中指定加密方式(.ini配置文件,和spring整合以后会在applicationContext.xml中id="jdbcRealm")
最终密码匹配是在SimpleCredentialsMatcher.class进行-->实现CredentialsMatcher(I)
SimpleCredentialsMatcher.class下有一个子类,一旦使用指定shiro用MD5对密码进行加密的配置以后,密码匹配会在 Md5CredentialsMatcher.class中进行
Md5CredentialsMatcher.class已经将来被废弃,所以
since 1.1 - use the HashedCredentialsMatcher directly and set its
最终对密码进行加密和匹配HashedCredentialsMatcher进行实现
如何对明文密码进行加密
6.2.1.从前端获取到用户输入的密码-->通过doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info)进行密码比对
当进入方法的第一个参数时:AuthenticationToken-->首先会到org.apache.shiro.authc.credential.HashedCredentialsMatcher进行加密-->返回被加密过的密码
-->返回给AuthenticationToken token
-->进行对比AuthenticationToken token和AuthenticationInfo info(从数据库查询出的密码进行对比)
shiro使用哪一种方式对密码进行明文加密(MD5)
6.2.2.<!-- 指定密码的加密算法为MD5 -->
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!-- hashAlgorithmName:指定了shiro的加密方式,默认就是MD5,如果需要使用其他的加密方式,就必须自定义实现 -->
<property name="hashAlgorithmName" value="MD5"></property>
<!--指定使用MD5加密的次数-->
<property name="hashIterations" value="1024"></property>
</bean>
</property>
开启shiro的加密方式
6.2.3.因为如果两个用户的密码相同,MD5加密后存入数据库也相同,需要使用"颜值"加密
user.getPassword():从数据库中查询出的密码
ByteSource.Util.bytes("1"):颜值
ByteSource类型(I)
里面会有一个内部实现类,可以构造出ByteSource实例对象
This is slightly nicer than needing to know the implementation class to use.
如果获取到颜值?
ByteSource.Utils.bytes("字符串类型");返回值就是颜值所需要的类型(ByteSource)
使用new SimpleAuthenticationInfo(username, user.getPassword(), ByteSource.Util.bytes("1"), getName());
7.授权
7.1.因为AuthenticatingRealm只做认证功能,那么授权在同一个class中无法处理
7.2.授权需要使用到的class是AuthenticatingRealm一个子类AuthorizingRealm
AuthorizingRealm.class既可以进行认证功能,也可以进行授权的功能
LoginHandler.java:
package com.zzsxt.lee.web.shiro.controller; import javax.servlet.http.HttpSession; 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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import com.zzsxt.lee.web.shiro.service.TestService; @Controller
public class LoginHandler { @Autowired
private TestService testService; @RequestMapping("/login.action")
public String login(@RequestParam("username") String username, @RequestParam("password") String password) { // 开始进行登录
System.out.println("我是处理登录请求的方法,我被访问过"); Subject currentUser = SecurityUtils.getSubject();
// let's login the current user so we can check against roles and
// AuthenticatingRealm permissions:
// currentUser.isAuthenticated()当前用户是否被认证
// 如果当前用户被认证了,说明用户还是处于登录状态
if (!currentUser.isAuthenticated()) {
// 如果没有被认证,开始登录
// 把需要登录的用户名和密码存入shiro提供的令牌中
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
// subject调用login方法来进行匹配用户是否可以登录成功
// login方法的参数需要接收shiro的UsernamePasswordToken类型
currentUser.login(token);
} catch (AuthenticationException ae) {
System.out.println("登录失败!" + ae.getMessage());
}
}
return "redirect:success.jsp";
} @RequestMapping("/annotation.action")
public String ViewAdminPage(HttpSession session) {
session.setAttribute("user", "lisi");
// 如果没有权限调用test()方法的时候,就直接抛出异常
try {
testService.test();
} catch (Exception e) {
e.getMessage();
return "redirect:unauthorized.jsp";
}
return "redirect:success.jsp";
} }
User.java:
package com.zzsxt.lee.web.shiro.model; import java.io.Serializable; public class User implements Serializable {
private static final long serialVersionUID = 3978937578087629248L; private Long id;
private String username;
private String password;
private Integer age;
private Integer lockedUser; public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
} public Integer getLockedUser() {
return lockedUser;
} public void setLockedUser(Integer lockedUser) {
this.lockedUser = lockedUser;
} @Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((age == null) ? 0 : age.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((lockedUser == null) ? 0 : lockedUser.hashCode());
result = prime * result + ((password == null) ? 0 : password.hashCode());
result = prime * result + ((username == null) ? 0 : username.hashCode());
return result;
} @Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (age == null) {
if (other.age != null)
return false;
} else if (!age.equals(other.age))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (lockedUser == null) {
if (other.lockedUser != null)
return false;
} else if (!lockedUser.equals(other.lockedUser))
return false;
if (password == null) {
if (other.password != null)
return false;
} else if (!password.equals(other.password))
return false;
if (username == null) {
if (other.username != null)
return false;
} else if (!username.equals(other.username))
return false;
return true;
} @Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", password=" + password + ", age=" + age + ", lockedUser="
+ lockedUser + "]";
} }
ShiroRealm.java:
package com.zzsxt.lee.web.shiro.reamls; import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.realm.Realm; /**
* @description 实现Realm接口
* @author Seven Lee
* @date 2017年9月21日 下午2:11:56
*
*/
public class ShiroRealm implements Realm { @Override
public AuthenticationInfo getAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
return null;
} @Override
public String getName() {
return null;
} @Override
public boolean supports(AuthenticationToken arg0) {
return false;
}
}
ShiroRealm2.java:
package com.zzsxt.lee.web.shiro.reamls; 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.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.util.ByteSource; import com.zzsxt.lee.web.shiro.model.User; public class ShiroRealm2 extends AuthenticatingRealm { @Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// token从controller中调用login(UsernamePasswordToken)传递过来
// 1.把AuthenticationToken类型的token转换为UsernamePasswordToken
// upToken:封装了从前端传递的用户名和密码(用户输入)
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
// 2.通过UsernamePasswordToken获取username
String username = upToken.getUsername();
// 3.通过username查询数据库
System.out.println("从数据库中匹配username:" + username); // 4.如果没有查询到用户对象信息,就抛出找不到用户异常UnknownAccountException
// 模拟通过username已经从数据库中查询出了User对象,而且用户存在
User user = new User();
user.setId(1L);
user.setUsername("zhangsan");
user.setPassword("123456");
user.setAge(17);
user.setLockedUser(0); if (!user.getUsername().equals(username)) {
throw new UnknownAccountException("该用户不存在");
}
// 5.如果用户存在-->根据查询用户信息的情况,抛出其他的异常(该用户已经被锁定,用户锁定异常LockedAccountException)
if (user.getLockedUser() == 1) {
throw new LockedAccountException("该用户被锁定");
}
// 6.返回AuthenticationInfo类型的数据
// principal:查询出的用户实体类对象,也可以是用户名
// credentials:用户的密码
// realmName:realm的name
// SimpleAuthenticationInfo sact = new SimpleAuthenticationInfo(username, user.getPassword(), getName());
SimpleAuthenticationInfo sact = new SimpleAuthenticationInfo(username, user.getPassword(), ByteSource.Util.bytes("1"), getName());
return sact;
} public static void main(String[] args) {
// e10adc3949ba59abbe56e057f20f883e加密一次后的123456的密码
// fc1709d0a95a6be30bc5926fdb7f22f4加密1024次后的123456的密码
// ee74a75f182c46effa1a4b350d537566加完盐值(ByteSource.Util.bytes("1"))后的密码
User user = new User();
user.setId(1L);
new SimpleHash("MD5", "123456", ByteSource.Util.bytes("1"), 1024);
}
}
ShiroRealm3.java:
package com.zzsxt.lee.web.shiro.reamls; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource; import com.zzsxt.lee.web.shiro.model.User; public class ShiroRealm3 extends AuthorizingRealm { /**
* @description 认证(登录功能)
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// token从controller中调用login(UsernamePasswordToken)传递过来
// 1.把AuthenticationToken类型的token转换为UsernamePasswordToken
// upToken:封装了从前端传递的用户名和密码(用户输入)
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
// 2.通过UsernamePasswordToken获取username
String username = upToken.getUsername();
// 3.通过username查询数据库
System.out.println("从数据库中匹配username:" + username); // 4.如果没有查询到用户对象信息,就抛出找不到用户异常UnknownAccountException
// 模拟通过username已经从数据库中查询出了User对象,而且用户存在
User user1 = new User();
user1.setId(1L);
user1.setUsername("zhangsan");
user1.setPassword("ee74a75f182c46effa1a4b350d537566");
user1.setAge(17);
user1.setLockedUser(0); User user2 = new User();
user2.setId(1L);
user2.setUsername("lisi");
user2.setPassword("ee74a75f182c46effa1a4b350d537566");
user2.setAge(20);
user2.setLockedUser(0); if (!user2.getUsername().equals(username)) {
throw new UnknownAccountException("该用户不存在");
}
// 5.如果用户存在-->根据查询用户信息的情况,抛出其他的异常(该用户已经被锁定,用户锁定异常LockedAccountException)
if (user2.getLockedUser() == 1) {
throw new LockedAccountException("该用户被锁定");
}
// 6.返回AuthenticationInfo类型的数据
// principal:查询出的用户实体类对象,也可以是用户名
// credentials:用户的密码
// realmName:realm的name
// SimpleAuthenticationInfo sact = new
// SimpleAuthenticationInfo(username, user.getPassword(), getName());
// 在认证中的第一个参数:
// 可以是Username也可以是User实体类对象
// 如果传的参数为username,那么在授权阶段,使用principals.getPrimaryPrincipal();获取到的就是Username
SimpleAuthenticationInfo sact = new SimpleAuthenticationInfo(user2.getUsername(), user2.getPassword(),
ByteSource.Util.bytes("1"), getName());
return sact;
} /**
* @description 授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 1.通过principals获取已经认证完毕的用户名
//String username = (String) principals.getPrimaryPrincipal();
// 2.根据用户名去数据库中查询该认证用户下角色/权限信息
// Set<String> roles = new HashSet<String>();
// roles.add("user");
// if ("zhangsan".equals(username)) {
// roles.add("admin");
// }
List<String> permissionList = new ArrayList<String>();
permissionList.add("menu:book");
// 3.把角色/权限信息封装进SimpleAuthorizationInfo.class
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//info.addRoles(roles);
info.addStringPermissions(permissionList);
// 4.返回SimpleAuthorizationInfo.class
return info;
} }
TestService.java:
package com.zzsxt.lee.web.shiro.service; import java.util.Date; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresRoles; /**
* @description @Service是spring的注解,和shiro并没有关系
* @RequiresRoles是shiro的注解,如果要使用shiro的注解,就一定要在shiro的配置文件中进行配置
* 再由shiro一同交给spring进行托管
* 如果想使用shiro权限注解,必须要在shiro配置文件中进行配置,配置这个TestService.class
* <bena id="xxx" class="xx.xxx.xx.xx.Xxx.class"></bean>
* @author Seven Lee
* @date 2017年9月22日 下午4:14:52
*
*/
public class TestService { @RequiresRoles({ "admin" })
public void test() {
System.out.println("------------------------" + new Date().toString() + "------------------------");
String username = (String) SecurityUtils.getSubject().getSession().getAttribute("user");
System.out.println(username);
}
}
applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context" xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"> <!-- ========================================================= Shiro Core
Components - Not Spring Specific ========================================================= -->
<!-- Shiro's main business-tier object for web-enabled applications (use
DefaultSecurityManager instead when there is no web environment) -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="cacheManager" ref="cacheManager" />
<property name="sessionMode" value="native" />
<property name="realm" ref="jdbcRealm" />
</bean>
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:ehcache.xml" />
</bean>
<bean id="jdbcRealm" class="com.zzsxt.lee.web.shiro.reamls.ShiroRealm3">
<!-- 指定密码的加密算法为MD5 -->
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!-- hashAlgorithmName:指定了shiro的加密方式,默认就是MD5,如果需要使用其他的加密方式,就必须自定义实现 -->
<property name="hashAlgorithmName" value="MD5"></property>
<!--指定使用MD5加密的次数 -->
<property name="hashIterations" value="1024"></property>
</bean>
</property>
</bean> <!-- ========================================================= Shiro Spring-specific
integration ========================================================= -->
<!-- 最终shiro的生命周期由spring的ioc容器进行托管 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> <!-- Enable Shiro Annotations for Spring-configured beans. Only run after
the lifecycleBeanProcessor has run: -->
<!-- 默认自动代理生成器(生成shiro对象) 开启shiro注解 必须要配置在lifecycleBeanPostProcessor之后 -->
<bean
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor" /> <!-- 配置 securityManager 可以用注解的形式实现 -->
<bean
class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<!-- securityManager:subject -->
<property name="securityManager" ref="securityManager" />
</bean> <!-- 这就是和你们至关重要的配置文件了!!!!! 和以后的java代码有关系 shiroFilter securityManager loginUrl:登录的路径
successUrl:登录成功跳转的路径 unauthorizedUrl:如果该用户没有权限,需要跳转的页面 -->
<!-- <bean id="shiroFilter">和web.xml的<filter-name>shiroFilter</filter-name>保持一致
如果配置的不一致 报错org.springframework.beans.factory.NoSuchBeanDefinitionException:
No bean named 'shiroFilter' is defined -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/login.jsp" />
<property name="successUrl" value="/success.jsp" />
<!-- 在授权阶段才能进入该页面 如果已经认证没有权限的时候,才会触发 -->
<property name="unauthorizedUrl" value="/unauthorized.jsp" />
<!-- anon:如果用户匿名访问也可以访问成功 shiro直接放行,并不需要认证和授权 /login.jsp:路径 /login.jsp
= anon:login页面不需要认证和授权,可以直接访问 authc:如果访问该路径,就必须要认证和授权 /**:所有的路径 /login.jsp
= anon /** = authc 只有login.jsp不需要拦截,其他一切路径都需要进行认证和授权 /路径 = roles[admin] -->
<property name="filterChainDefinitions">
<value>
<!-- shiro拦截配置优先选举规则 如果把/**配置到前面 后面所有配置都失效 如果配置的不是/** shiro会默认覆盖前面的配置 -->
/login.* = anon
/logout = logout
<!-- roles[admin,user]
猜想:
如果roles[]中配置了两个角色,那么被认证的用户就必须拥有这两个角色才能正常访问该角色下路径
否则,就会被跳转到无权限页面
因为zhangsan用户即拥有user角色又拥有admin角色,所以能够访问该路径
如果把zhangsan用户下的user角色给删除调,则不能访问该路径
猜想正确
-->
<!-- /success.jsp= roles[user] -->
/** = authc
</value>
</property>
</bean> <bean id="testService" class="com.zzsxt.lee.web.shiro.service.TestService"></bean>
</beans>
ehcache.xml:
<!--
~ Licensed to the Apache Software Foundation (ASF) under one
~ or more contributor license agreements. See the NOTICE file
~ distributed with this work for additional information
~ regarding copyright ownership. The ASF licenses this file
~ to you under the Apache License, Version 2.0 (the
~ "License"); you may not use this file except in compliance
~ with the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
--> <!-- EhCache XML configuration file used for Shiro spring sample application -->
<ehcache> <!-- Sets the path to the directory where cache .data files are created. If the path is a Java System Property it is replaced by
its value in the running VM. The following properties are translated:
user.home - User's home directory
user.dir - User's current working directory
java.io.tmpdir - Default temp file path -->
<diskStore path="java.io.tmpdir/shiro-spring-sample"/> <!--Default Cache configuration. These will applied to caches programmatically created through
the CacheManager. The following attributes are required: maxElementsInMemory - Sets the maximum number of objects that will be created in memory
eternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the
element is never expired.
overflowToDisk - Sets whether elements can overflow to disk when the in-memory cache
has reached the maxInMemory limit. The following attributes are optional:
timeToIdleSeconds - Sets the time to idle for an element before it expires.
i.e. The maximum amount of time between accesses before an element expires
Is only used if the element is not eternal.
Optional attribute. A value of 0 means that an Element can idle for infinity.
The default value is 0.
timeToLiveSeconds - Sets the time to live for an element before it expires.
i.e. The maximum time between creation time and when an element expires.
Is only used if the element is not eternal.
Optional attribute. A value of 0 means that and Element can live for infinity.
The default value is 0.
diskPersistent - Whether the disk store persists between restarts of the Virtual Machine.
The default value is false.
diskExpiryThreadIntervalSeconds- The number of seconds between runs of the disk expiry thread. The default value
is 120 seconds.
memoryStoreEvictionPolicy - Policy would be enforced upon reaching the maxElementsInMemory limit. Default
policy is Least Recently Used (specified as LRU). Other policies available -
First In First Out (specified as FIFO) and Less Frequently Used
(specified as LFU)
--> <defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
/> <!-- We want eternal="true" (with no timeToIdle or timeToLive settings) because Shiro manages session
expirations explicitly. If we set it to false and then set corresponding timeToIdle and timeToLive properties,
ehcache would evict sessions without Shiro's knowledge, which would cause many problems
(e.g. "My Shiro session timeout is 30 minutes - why isn't a session available after 2 minutes?"
Answer - ehcache expired it due to the timeToIdle property set to 120 seconds.) diskPersistent=true since we want an enterprise session management feature - ability to use sessions after
even after a JVM restart. -->
<cache name="shiro-activeSessionCache"
maxElementsInMemory="10000"
eternal="true"
overflowToDisk="true"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="600"/> <cache name="org.apache.shiro.realm.SimpleAccountRealm.authorization"
maxElementsInMemory="100"
eternal="false"
timeToLiveSeconds="600"
overflowToDisk="false"/> </ehcache>
log4j.properties:
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
log4j.rootLogger=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n # General Apache libraries
log4j.logger.org.apache=WARN # Spring
log4j.logger.org.springframework=WARN # Default Shiro logging
log4j.logger.org.apache.shiro=TRACE # Disable verbose logging
log4j.logger.org.apache.shiro.util.ThreadContext=WARN
log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN
shiro-servlet.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <context:component-scan base-package="com.zzsxt.lee.web.shiro"></context:component-scan> <mvc:default-servlet-handler />
<mvc:annotation-driven></mvc:annotation-driven> <!-- Jsp视图解析器 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1"> <!--spring入口文件的配置 -->
<!-- 确定配置文件位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param> <!-- shiro入口程序 -->
<filter>
<filter-name>shiroFilter</filter-name>
<!--
init(Config config){
String targetBeanName = shiroFilter;
}
-->
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
<!-- 第二种配置<bean id="">
在web.xml中的filter标签里配置<init-param></init-param>
<param-name>targetBeanName</param-name>一定写规范
<param-value>abc</param-value>指向了<bean>的id
-->
<!-- <init-param>
<param-name>targetBeanName</param-name>
<param-value>abc</param-value>
</init-param> -->
</filter> <filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> <!-- 配置spring 监听器,加载xml配置文件 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> <!-- DispatcherServlet:前端控制器 配置前端控制器servlet -->
<servlet>
<servlet-name>shiro</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 表示随WEB服务器启动 -->
<load-on-startup>1</load-on-startup>
</servlet> <servlet-mapping>
<servlet-name>shiro</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping> <display-name>20170921_shiro_spring</display-name>
</web-app>
admin.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>"> <title>My JSP 'login.jsp' starting page</title> </head> <body>
<h1>Admin Page</h1>
</body>
</html>
login.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>"> <title>My JSP 'login.jsp' starting page</title> </head> <body>
<h1>Login Page</h1>
<form action="/zzsxt/login.action" method="post">
Username:<input type="text" name="username" /><br /> Password:<input
type="password" name="password" /><br /> <input type="submit"
value="submit" />
</form>
</body>
</html>
success.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>"> <title>My JSP 'login.jsp' starting page</title> </head> <body>
<h1>Success Page</h1>
<!-- shiro:principal
从shiro中取出认证后传递到授权中的对象-可以为实体对象,也可以是username
property="password":从认证中传递来的实体对象的属性(User:username,passowrd,age,lockedUser...)
如果从认证传递过来的是一个username的话,则无需property="password"属性
-->
<h4>Welcome:<shiro:principal></shiro:principal></h4>
<!-- shiro:guest
无需认证直接可以访问
-->
<shiro:guest>
<a href="">登录</a>
</shiro:guest>
<shiro:hasRole name="admin">
<shiro:hasPermission name="menu:books">
<a href="/zzsxt/admin.action">admin page</a>
</shiro:hasPermission>
<shiro:hasPermission name="menu:book">
<a href="/zzsxt/admin.action">user page</a>
</shiro:hasPermission>
</shiro:hasRole>
<a href="/zzsxt/user.jsp">user page</a>
<a href="/zzsxt/annotation.action">测试注解</a>
<a href="/zzsxt/logout">登出</a>
</body>
</html>
unauthorized.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>"> <title>My JSP 'login.jsp' starting page</title> </head> <body>
<h1>Unauthorized Page</h1>
</body>
</html>
user.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>"> <title>My JSP 'login.jsp' starting page</title> </head> <body>
<h1>User Page</h1>
</body>
</html>
java:shiro(认证,赋予角色,授权...)的更多相关文章
- Shiro认证、角色、权限
Apache Shiro 是 Java 的一个安全框架.Shiro 可以帮助我们完成:认证.授权.加密.会话管理.与 Web 集成.缓存等. Shiro的内置Realm:IniRealm和JdbcRe ...
- shiro认证策略,授权
有具体问题的可以参考之前的关于shiro的博文,关于shiro的博文均是一次工程的内容 ! 认证策略: 修改认证策略: applicationContext.xml <!-- 认证器 --> ...
- ASP.NET 表单认证与角色授权
参考 : http://hi.baidu.com/iykqqlpugocfnqe/item/e132329bdea22acbb6253105 ASP.NET中处理请求的流程图 http://www. ...
- Apache Shiro 认证+授权(一)
1.核心依赖 <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-co ...
- 源码分析shiro认证授权流程
1. shiro介绍 Apache Shiro是一个强大易用的Java安全框架,提供了认证.授权.加密和会话管理等功能: 认证 - 用户身份识别,常被称为用户“登录”: 授权 - 访问控制: 密码加密 ...
- 【shiro】(4)---Shiro认证、授权案例讲解
Shiro认证.授权案例讲解 一.认证 1. 认证流程 2.用户密码已经加密.加盐的用户认证 (1)测试类 // 用户登陆和退出,这里我自定了一个realm(开发肯定需要自定义realm获取 ...
- 转:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法、shiro认证与shiro授权
原文地址:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法.shiro认证与shiro授权 以下是部分内容,具体见原文. shiro介绍 什么是shiro shiro是Apache ...
- shiro框架学习-2-springboot整合shiro及Shiro认证授权流程
1. 添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...
- 【Java EE 学习 76 上】【数据采集系统第八天】【角色授权】【用户授权】【权限的粗粒度控制】【权限的细粒度控制】
一.角色管理 单击导航栏上的"角色管理"超链接,跳转到角色管理界面,在该界面上显示所有角色,并提供角色的增加和删除.修改超链接. 1.增加新角色(角色授权) 流程:单击增加新角色超 ...
随机推荐
- sql 178. 分数排名
编写一个 SQL 查询来实现分数排名.如果两个分数相同,则两个分数排名(Rank)相同.请注意,平分后的下一个名次应该是下一个连续的整数值.换句话说,名次之间不应该有“间隔”. +----+----- ...
- 如何用eclipse进行jar文件打包?
直接导出runnable jar,如下图所示: 然后选择导出runnable jar: 关于library handling部分的解释如下: (1)Extract required libraries ...
- 2 APIView与序列化组件
1.入门 1.1 参考blog 官方文档:http://www.django-rest-framework.org/tutorial/quickstart/#quickstart yuan的Blog: ...
- 网页分享到微信、微博、QQ空间、百度贴吧等
1.首先说明的是,pc端微信分享只能通过二维码来分享. 2.下面是js代码. //分享到新浪微博 function shareToSinaWB(event){ event.preventDefault ...
- 炫酷CSS3垂直时间轴特效
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Vue_(组件通讯)子组件向父组件传值
Vue组件 传送门 子组件向父组件传值:子组件通过$.emit()方法以事件形式向父组件发送消息传值: 使用步骤: 1.定义组件:现有自定义组件com-a.com-b,com-a是com-b的父组件: ...
- phpcms9 从注入点入手和 从前台getshell
弄了3天了 这个点 总结一下这三天的坑吧 0X01 注入点入手 /index.php?m=wap&c=index&a=init&siteid=1 获取cookie 传给 us ...
- Runtime Error R6034 Application has attempt to load the C runtime library incorrectly
1.问题描述 vs2015 去开发一个写入pg数据库的程序,使用libpqxx.dll,libpq.dll,这个库文件之前是用vs2008的程序中复制过来的,基于的运行时库应该是vs2008,现在开发 ...
- linux如何模糊查找一个文件
在当前目录下搜索指定文件: find . -name test.txt 在当前目录下模糊搜索文件: find . -name '*.txt' 在当前目录下搜索特定属性的文件: find . -amin ...
- 使用Jmeter对观影券查询接口做性能测试
线程数:虚拟用户数.一个虚拟用户占用一个进程或线程.设置多少虚拟用户数在这里也就是设置多少个线程数. 准备时长: 设置的虚拟用户数需要多长时间全部启动.如果线程数为20 ,准备时长为10 ,那么需要1 ...