[今日课程大纲]
Shiro简介及架构图讲解
ini配置文件讲解
Shiro搭建及简单认证实现
加密及凭证匹配器
Spring整合Shiro完成登录功能.
[知识点详解]
1. Shiro官网介绍
1.1 中文:Apache Shiro是一个强大的并且简单使用的java权限框架.主要应用认证(Authentication),授权(Authorization),cryptography(加密),和Session Manager.Shiro具有简单易懂的API,使用Shiro可以快速并且简单的应用到任何应用中,无论是从最小的移动app到最大的企业级web应用都可以使用.
2.1 Authentication:认证.用户的登录,退出属于认证.
2.2 Authorization:授权.菜单授权,元素可见性授权等.
2.3 Cryptography:加密.密码加密,md5加密等.
2.4 Session Management: Session管理
2.5 Web Integration : Web集成.
2.5.1 Shiro不依赖于容器的,可以运行在JavaSE的环境中.
3.1 最上面部分表示Shiro支持各种类型的语言.
3.2 Subject:主体.每个用户登录后都会对应一个Subject对象,所有用户信息都存储到Subject中.
3.3 Security Manager:Shiro最大的容器.Shiro所有功能都封装在Security Manager中.
3.3.1 编写代码时,想要使用Shiro第一个步骤获取到Security Manager
3.3.2 在整个程序中保证Security Manager有且只有一个.
3.4 Authenticator: 认证器.执行认证过程调用的组件.
3.5 Authorizer:授权器.执行授权时调用的组件.
3.6 Session Manager: Session管理器.
3.7 Cache Manager: 缓存管理器.Shiro支持很多第三方缓存工具.例如Ehcache等.
3.8 SessionDao: 操作Session内容的组件.
3.9 Realm:该组件的作用负责获取到数据库中数据并根据用户自定义逻辑进行授权和认证等操作.
3.9.1 Shiro 框架和数据库没有关系.没有对数据库设计有认证强制要求.
3.9.2 如果Shiro想要访问数据库都是通过Realm组件.
3.9.3 如果Shiro数据不是来源于数据库,可以使用.ini文件设置静态数据.
5.1 [main] 主体部分.
5.1.1 这部分配置类对象,或设置属性等操作.
5.1.2 内置了根对象,securityManager
5.1.3 语法:
[main] securityManager.属性=值 key=value securityManager.对象属性=com.bjsxt.pojo.People #后面值是字符串
peo=com.bjsxt.pojo.People securityManager.对象属性=$peo #出现$时才表示是引用对象 |
5.2 [users] 定义用户,密码及用户可以具有的角色.
5.2.1 语法:
[users] 用户名=密码,角色1,角色2 #角色部分可以省略. zhangsan=zs zhangsan=zs,role1,role2 |
5.3 [roles] 定于角色具有的权限
[roles] 角色名=权限名,权限名 role1=user:insert,user:update role2=insert,update role3=user:* |
5.4 [urls] 定义哪个控制器被哪个过滤器过滤.
[urls] 控制器名称=过滤器名称 /login=authc /**=anon |
4.1 如果认证是返回值为null,认证认证时账户不存在.
5.1 在pom.xml中依赖shiro-core
<dependencies> <dependency> <groupId>org.apache.shirogroupId> <artifactId>shiro-coreartifactId> <version>1.3.2version> dependency> dependencies> |
5.2 在java/main/resources创建shiro配置文件shiro.ini
[users] zhangsan=zs lisi=ls |
5.3 编写认证测试代码
5.3.1 SecurityUtils主要作用能够保证Subject在线程容器中.随时取出Subject
public static void main(String[] args) { //创建工厂 Factory //创建容器 SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager); //底层使用ThreadLocal所以只要线程不变,可以在任何位置获取到Subject对象. Subject subject = SecurityUtils.getSubject();
//执行登录 AuthenticationToken token = new UsernamePasswordToken("zhangs123an", "zs"); //login方法没有返回值,通过抛出异常告诉用户是什么问题 //org.apache.shiro.authc.UnknownAccountException 帐号不存在 //org.apache.shiro.authc.IncorrectCredentialsException 密码错误 try { subject.login(token); System.out.println("登录成功"); } catch (UnknownAccountException e) { e.printStackTrace(); System.out.println("账户不正确"); }catch(IncorrectCredentialsException e){ System.out.println("密码不正确"); } } |
public static void main(String[] args) { String password="zs"; Md5Hash md5Hash = new Md5Hash(password); System.out.println(md5Hash); //加密算法中著名"盐",在程序开发中盐值都是用户的ID等信息. //把原来的字符串和盐拼接,在对拼接的字符串进行加密. Md5Hash md5Hash2 = new Md5Hash(password, "123"); System.out.println(md5Hash2);
Md5Hash md5Hash3 = new Md5Hash(password, "123", 2); System.out.println(md5Hash3);
SimpleHash simpleHash = new SimpleHash("md5",password,"123",2); System.out.println(simpleHash); } |
4.1 algorithmName:算法名称
4.2 iterations:迭代几次
2.1 新建类.继承后具备认证和授权功能
public class MyRealm extends AuthorizingRealm |
2.2 doGetAuthenticationInfo(AuthenticationToken token)实现认证功能.
2.2.1 token.getPrincipal() 获取身份
2.2.2 new String((char[])token.getCredentials()) 获取凭证
2.2.3 如果返回值为null,抛出异常帐号不存在
2.2.4 如果返回值AuthenticationInfo第二个参数和login()时密码不一致,抛出异常.第二个参数设置从数据库查询出来的密码
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("执行认证"); //JDBC代码 System.out.println("principal:"+token.getPrincipal()); //先判断用户名是否存在 select * from users where username=? //判断查询结果,如果SQL命令查询结果为null,说明帐号不存在.return null; //如果SQL命令查询结果不为null.必须返回SimpleAuthenticationInfo,第二个参数写从数据库中查询出来的密码 //由Shiro判断第二个参数和token中密码是否匹配. //第三个参数.Map集合的key.当用户登录成功后会把用户的Principal存储到集合中,realmName就是集合key,把用户名当作realmName long id = 123; String username="zhangsan"; String password="5605c3b6f0dc63c2da52625e9d2ed2d2"; AuthenticationInfo info = new SimpleAuthenticationInfo(token.getPrincipal(), password,token.getPrincipal().toString());
System.out.println("Credentials:"+new String((char[])token.getCredentials()));
return info; } |
2.3 在shiro.ini中配置自定义Realm
[main]
myrealm=com.bjsxt.realm.MyRealm securityManager.realms=$myrealm |
1.1 第三个参数类型ByteSource类型
AuthenticationInfo info = new SimpleAuthenticationInfo(token.getPrincipal(), password,ByteSource.Util.bytes(id+"") ,token.getPrincipal().toString()); |
[main] credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher credentialsMatcher.hashAlgorithmName=md5 credentialsMatcher.hashIterations=2
myrealm=com.bjsxt.realm.MyRealm myrealm.credentialsMatcher=$credentialsMatcher securityManager.realms=$myrealm |
2.1 必须配置在web.xml
2.2 全局(初始化参数
2.3 targetFilterLifecycle默认值为false
3.1 securityManager 属性.
3.2 filterChainDefinitions 配置哪些URL进行什么样的权限操作
3.2.1 /login=authc
3.3 loginUrl:表示认证完成后如果认证失败跳转到哪里
3.3.1 内容必须是authc处理的url
3.4 successUrl:表示认证成功后跳转到哪里
4.1 如果希望自定义Realm,需要给属性realms赋值.
5.1 配置属性credentialsMatcher,引用另一个
6.1 配置算法:hashAlgorithmName
6.2 配置迭代次数:hashIterations
7.1 如果认证失败把异常信息放入到request作用域中,并设置key为下面
7.2 如果希望FormAuthenticationFilter生效,表单中用户名必须叫做username,密码必须叫做password
|
|
|
|
结束 |
|
|
开始 |
请求/login控制器 |
DelegatingFilterProxy过滤 |
securityManager,让shiro生效 |
<dependency> <groupId>org.apache.shirogroupId> <artifactId>shiro-coreartifactId> <version>1.3.2version> dependency> <dependency> dependency> <dependency> <groupId>org.apache.shirogroupId> <artifactId>shiro-springartifactId> <version>1.3.2version> dependency> |
<filter> <filter-name>shirofilter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class> <init-param> <param-name>targetBeanNameparam-name> <param-value>shiroFilterparam-value> init-param> <init-param> <param-name>targetFilterLifecycleparam-name> <param-value>trueparam-value> init-param> filter> <filter-mapping> <filter-name>shirofilter-name> <url-pattern>/*url-pattern> filter-mapping> |
public class MyShiroRealm extends AuthorizingRealm{ @Autowired private UsersService usersService;
@Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // TODO Auto-generated method stub return null; } //认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("usersService:"+usersService); System.out.println("zhixing认证"); String principal = token.getPrincipal().toString(); System.out.println("principal:"+principal); Users user = usersService.login123(principal); System.out.println("dubbo调用陈功"); if(user!=null){ System.out.println("if"); AuthenticationInfo info= new SimpleAuthenticationInfo(token.getPrincipal(), user.getPassword(),ByteSource.Util.bytes(user.getId()+""),token.getPrincipal().toString()); return info; }else{ System.out.println("else"); //表示用户名不存在 return null; } } } |
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <property name="hashAlgorithmName" value="md5">property> <property name="hashIterations" value="2">property> bean> <bean id="myShiroRealm" class="com.bjsxt.manage.realm.MyShiroRealm"> <property name="credentialsMatcher" ref="credentialsMatcher">property> bean> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realms" ref="myShiroRealm">property> bean> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager">property> <property name="loginUrl" value="/login">property> <property name="successUrl" value="/loginSuccess">property> <property name="filterChainDefinitions"> <value> /login=authc /**=anon value> property> bean> |
@RequestMapping("login") @ResponseBody public int login(HttpServletRequest request){ Object obj = request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME); System.out.println("obj:"+obj); if(obj!=null){ if(obj.equals(UnknownAccountException.class.getName())){ //账户不正确. return 1; }else if(obj.equals(IncorrectCredentialsException.class.getName())){ //密码不正确. return 2; } } return 3; } /** * 成功 * @return */ @RequestMapping("loginSuccess") @ResponseBody public int loginSuccess(){ System.out.println("执行success"); return 4; } |
7.1 在applicationCOntext-dubbo.xml中修改如下
<dubbo:reference id="usersDubboService" interface="com.bjsxt.dubbo.service.UsersDubboService" >dubbo:reference> <context:component-scan base-package="com.bjsxt.manage.service.impl">context:component-scan> |
7.2 在bjsxt-manage的Service实现类修改如下
@Autowired // @Reference private UsersDubboService usersDubboService; |