DispatcherServlet
前端控制器Shiro不提供维护用户 / 权限,而是通过Realm让开发人员自己注入内部结构
<dependencies>
<!--Junit 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- Shiro核心包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.3.2</version>
</dependency>
<!-- slf4j的接口实现 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
</dependencies>
[users]
root=yubuntu0109
/**
* Shiro认证测试:验证用户登录信息
*/
public class ShiroTest {
@Test
public void testLogin() {
//1:加载配置文件,创建SecurityManager工厂对象
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
//2:获得securityManager实例对象
SecurityManager securityManager = factory.getInstance();
//3:将securityManger实例绑定到当前运行环境中,便于访问
SecurityUtils.setSecurityManager(securityManager);
//4:创建当前登录的主体
Subject currentUser = SecurityUtils.getSubject();
//5:绑定主体登录的身份/凭证,既账户及密码(相当于从前台form表单获取到的账号密码)
UsernamePasswordToken token = new UsernamePasswordToken("root", "yubuntu0109");
//6:主体登录
try {
currentUser.login(token);
System.out.println("用户身份是否验证成功 :" + currentUser.isAuthenticated());
} catch (UnknownAccountException e) {
System.err.println("用户账户信息错误 !");
} catch (IncorrectCredentialsException e) {
System.err.println("用户密码信息错误 !");
} catch (AuthenticationException e) {
e.printStackTrace();
}
//8:注销登录
currentUser.logout();
System.out.println("身份身份是否注销成功 :" + !currentUser.isAuthenticated());
}
}
subject.login(AuthenticationToken token)
方法进行用户登录,其会自动委托给securityManager.login(Subject subject, AuthenticationToken token)
方法进行登录securityManager
(安全管理器)通过Authenticator
(认证器)进行认证Authenticator
的实现类ModularRealmAuthenticator
通过调用realm
从shiro.ini
配置文件中获取用户真实的信息(账户和密码),这里的Realm(域)可以看成DataSource,即安全数据源IniRealm
(可通过加载.ini
文件生成reaml对象)先根据token
中的账号去shiro.ini
配置文件中去匹配该账号,如果找不到则ModularRealmAuthenticator
返回null,如果找到则继续匹配密码,若匹配成功则认证通过,反之不通过Subject.logout()
进行退出操作org.apache.shiro.realm.text.IniRealm
接口//org.apache.shiro.realm.Realm接口
//返回一个唯一的Realm名字
String getName();
//判断此Realm是否支持此Token
boolean supports(AuthenticationToken token);
//根据Token获取认证信息
AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException;
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- Shiro核心包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.3.2</version>
</dependency>
<!-- slf4j的接口实现 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
<!-- java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
#自定义realm
myRealm = com.xxx.MyRealm
#指定SecurityManager的realms实现
securityManager.realm = $myRealm
public class MyRealm extends AuthorizingRealm {
@Override
public String getName() {
return "myRealm"; //区分不同的Realm
}
@Override
//授权操作
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
@Override
//认证操作:其token存储着传入的用户登录信息(usernamePasswordToken)
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取并验证用户账号信息(前端传入)
String username = (String) token.getPrincipal();
//与数据库中的数据进行比较
if (!"root".equals(username)) {
return null;
}
//假设数据库中用户密码信息
String password = "yubuntu0109";
//SimpleAuthenticationInfo(Object principal, Object credentials, String realmName)
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, getName());
return info;
}
}
/**
* 测试自定义realm
*/
public class loginByMyRealm {
public static void main(String[] args) {
//1:加载配置文件,创建SecurityManager工厂对象
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:my-shiro.ini");
//2:获得securityManager实例对象
SecurityManager securityManager = factory.getInstance();
//3:将securityManger实例绑定到当前运行环境中,便于访问
SecurityUtils.setSecurityManager(securityManager);
//4:创建当前登录的主体
Subject currentUser = SecurityUtils.getSubject();
//5:绑定主体登录的身份/凭证,既账户及密码
UsernamePasswordToken token = new UsernamePasswordToken("root", "yubuntu0109");
//6:主体登录
try {
currentUser.login(token);
System.out.println("用户身份是否验证成功 :" + currentUser.isAuthenticated());
} catch (UnknownAccountException e) {
System.err.println("用户账户错误 !");
} catch (IncorrectCredentialsException e) {
System.err.println("用户密码错误 !");
} catch (AuthenticationException e) {
e.printStackTrace();
}
//8:注销登录
currentUser.logout();
System.out.println("身份身份是否注销成功 :" + !currentUser.isAuthenticated());
}
}
[main]
#定义凭证匹配器
credentialsMatcher = org.apache.shiro.authc.credential.HashedCredentialsMatcher
#散列算法
credentialsMatcher.hashAlgorithmName = md5
#散列次数
credentialsMatcher.hashIterations = 10
#将凭证匹配器设置到realm
myRealm = com.xxx.EncryRealm
myRealm.credentialsMatcher = $credentialsMatcher
securityManager.realms = $myRealm
/**
*加密realm
*/
public class EncryRealm extends AuthorizingRealm {
@Override
public String getName() {
return "myRealm"; //区分不同的Realm
}
@Override
//授权操作
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
@Override
//认证操作
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取用户账户信息
String username = token.getPrincipal().toString();
if (!"root".equals(username)) {
return null;
}
//MD5加密后的用户密码信息
String password = "f3005f7acf36cec973498845460b0c33";//password + username + 10
//指定盐值:ByteSource.Util.bytes(username)
return new SimpleAuthenticationInfo(username, password, ByteSource.Util.bytes(username), getName());
}
}
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole("admin")) {
//有权限
} else {
//无权限
}
@RequiresRoles("admin")
public void hello() {
//有权限
}
<shiro:hasRole name="admin">
<!— 有权限 —>
</shiro:hasRole>
Subject.isPermitted/hasRole
接口,其会委托给SecurityManager,而SecurityManager接着会委托给AuthorizerisPermitted(“user:create”)
,其首先会通过PermissionResolver把字符串转换成相应的Permission实例isPermitted/hasRole
会返回true,否则返回false以表示授权失败<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- Shiro核心包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.3.2</version>
</dependency>
<!-- slf4j的接口实现 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
<!-- java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
#权限表达式的定义:首先根据用户名查找角色,再根据角色查找权限,角色是权限的集合
[users]
#用户hunagyuhui的密码为loveyourself,且具有student和programmer两个角色
huangyuhui = loveyourself,student,programmer
[roles]
#角色student对资源'user'拥有create,update权限
student = user:create,user:update
#角色programmer对资源'user'read,delete权限
programmer = user:read,user:delete
public class RolesTest {
public static void main(String[] args) {
//1:加载配置文件,创建SecurityManager工厂对象
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:per-shiro.ini");
//2:获得securityManager实例对象
SecurityManager securityManager = factory.getInstance();
//3:将securityManger实例绑定到当前运行环境中,便于访问
SecurityUtils.setSecurityManager(securityManager);
//4:创建当前登录的主体
Subject currentUser = SecurityUtils.getSubject();
//5:绑定主体登录的身份/凭证,既账户及密码
UsernamePasswordToken token = new UsernamePasswordToken("huangyuhui", "loveyourself");
//6:主体登录
try {
currentUser.login(token);
System.out.println("用户身份是否验证成功 :" + currentUser.isAuthenticated());
//7:进行用户角色判断
System.out.println("判断当前登录用户是否拥有'student'角色 : " + currentUser.hasRole("student"));
System.out.println("判断当前登录用户是否同时拥有'student'与'programmer'角色 : " + currentUser.hasAllRoles(List.of("student", "programmer")));
System.out.println("判断当前登录用户是否拥有'student','programmer','singer'角色 : " + Arrays.toString(currentUser.hasRoles(List.of("student", "programmer", "singer"))));
//判断当前用户是否拥有某个角色,若拥有该角色则不做任何操作(无返回值),反之则抛出:UnauthorizedException
currentUser.checkRole("singer");
} catch (UnknownAccountException e) {
System.err.println("用户账户错误 !");
} catch (IncorrectCredentialsException e) {
System.err.println("用户密码错误 !");
} catch (UnauthorizedException e) {
System.err.println("用户并不拥有'singer'角色 !");
} catch (AuthenticationException e) {
e.printStackTrace();
}
//8:注销登录
currentUser.logout();
System.out.println("用户信息是否注销成功 :" + !currentUser.isAuthenticated());
}
}
/*
// ······
用户身份是否验证成功 :true
// ······
判断当前登录用户是否拥有'student'角色 : true
// ······
判断当前登录用户是否同时拥有'student'与'programmer'角色 : true
// ······
判断当前登录用户是否拥有'student','programmer','singer'角色 : [true, true, false]
// ······
用户并不拥有'singer'角色 !
// ······
用户信息是否注销成功 :true
*/
创建一个用户 software,然后给他分配权限,可以让 software 登录数据库、创建表、可以操作自己创建的表;回收角色,最后删除用户。
使用 system 创建 software 用户,密码设置为 system
create user software identified system;
要想让 software 登录(连接)数据库,需要给其 connect、session 权限(角色);
grant connect to software;
grant resource to software;
使用 software 用户登录
conn software/system@orcl
Software 创建一张表
create table users(id number)
删除 software 用户
drop user software [cascade]
注意:当 software 拥有自己的数据对象时,加上选项 cascade,一并把该用户拥有数据对象删除
完成一个功能,让 xiaohong 用户可以查询 scott 的 emp 表
Scott登录
conn scott/system
赋予权限
grant select[/update/delete/insert/all] on emp to xiaohong
xiaohong登录
conn xiaohong/system
小红查询 scott 的 emp 表
select * from scott.emp;
char(size)
varchar2(size)
变长,最大可存放4000个字符
nchar(size),nvarchar2(size)
n代表的意思是编码格式为Unicode编码,无论中文还是英文都用一个字符来存放数据
比如:“a”,占用一个字符,“软”,也是占用一个字符
clob(size)
变长,字符型的大对象,最大8tb
在varchar2不够用的情况下使用clob
blob(size)
变长,二进制数据,可以存放图片声音等,8tb
number(p,s)
变长,可以存放整数和小数
p表示有效位(从左开始),s表示小数位;范围:p[1,38],s[-84,127]
Number 可以表示的数值范围:-1.0e-130 ~~1.0e+126
占用机器码的空间是 1~22bytes
date
oracle dd-mm-yyyy
Sql->insert into test1(’01-1 月-14’);
timestamp(n)
邮戳的时间类型
与 date 区别,邮戳(timestamp)当某条数据更新时,使用邮戳字段也会自动更新。
通用模板:查询emp表中第4到6行数据
select t2.* from (select t1.empno,t1.ename,rownum rw from (select * from emp) t1 where rownum<=6 ) t2 where rw >=4;
请按照入职时间的先后进行排序,查询从 7 行到 10 行的雇员是谁。
select t2.* from (select t1.empno,t1.ename,rownum rw from (select * from emp order by hiredate) t1 where rownum<=10 ) t2 where rw >=7;
Union,union all,intersect,minus
Union
并集:该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中重复的行。
Union all
该操作符不会去掉重复行,而且不排序显示,重复的内容显示 2次。
select ename,sal,job from emp where sal>2500 union all select ename,sal,job from emp where job=’MANAGER’
Intersect
该操作符用于取得两个结果集的交集
Minus
使用该操作符用于取得两个结果集的差集,它只会显示存在第 1个集合中,而不存在第二个集合中的数据。
REPLACE(‘string’,’s1’,’s2’)
string:希望被替换的字符或变量
s1:被替换的字符串
s2 :要替换的字符串
INSTR(C1,C2,I,J)
在一个字符串中搜索指定的字符,返回发现指定的字符的位置;
C1:被搜索的字符串
C2:希望搜索的字符串
I :搜索的开始位置,默认为 1
J :出现的位置,默认为 1
ASCII(s)
返回与指定的字符对应的十进制数;
CHR(number)
给出整数,返回对应的字符;
CONCAT
连接两个字符串;
INITCAP
返回字符串并将字符串的第一个字母变为大写;
SUBSTR(string,start,count)
取子字符串,从 start 开始,取 count 个
LENGTH
返回字符串的长度;
LOWER
返回字符串,并将所有的字符小写
UPPER
返回字符串,并将所有的字符大写
Rpad 和 lpad 函数
RPAD 在列的右边粘贴字符
LPAD 在列的左边粘贴字符
不够字符则用*来填满
LTRIM 和 RTRIM 函数
LTRIM 删除左边出现的字符串
RTRIM 删除右边出现的字符串
CEIL(不是四舍五入,向上取整)
返回大于或等于给出数字的最小整数
FLOOR
对给定的数字取整数
MOD(n1,n2)
返回一个 n1 除以 n2 的余数
POWER(n1,n2)
返回 n1 的 n2 次方根
ROUND 和 TRUNC
按照指定的精度进行舍入
Round 四舍五入
Trunc 截取(可以指定截取到哪 1 位,没有指定的话,则默认截取到整数)
SYSDATE
用来得到系统的当前日期
TO_DATE(string,’format’)
将字符串转化为 ORACLE 中的一个日期
TO_NUMBER
将给出的字符转换为数字
@interface
关键字进行定义。public @interface TestAnnotation {
}
@TestAnnotation
public class Test {
}
它的取值如下:
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
}
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {}
@Test
public class A {}
public class B extends A {}
注解 Test 被 @Inherited 修饰,之后类 A 被 Test 注解,类 B 继承 A,类 B 也拥有 Test 这个注解。
可以这样理解:老子非常有钱,所以人们给他贴了一张标签叫做富豪。老子的儿子长大后,虽然别人没有给他贴标签,但是他自然也是富豪。这就是人们口中戏称的富一代,富二代,富三代。
@interface Persons {
Person[] value();
}
@Repeatable(Persons.class)
@interface Person{
String role default "";
}
@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{
}
//一个人他既是程序员又是产品经理,同时他还是个画家。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
int id();
String msg();
}
@TestAnnotation(id=3,msg="hello annotation")
public class Test {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
public int id() default -1;
public String msg() default "Hi";
}
public @interface Check {
String value();
}
@Check("hi")
int a;
//效果等同于
@Check(value="hi")
int a;
public @interface Perform {}
@Perform
public void testMethod(){}
@SafeVarargs // Not actually safe!
static void m(List<String>... stringLists) {
Object[] array = stringLists;
List<Integer> tmpList = Arrays.asList(42);
array[0] = tmpList; // Semantically invalid, but compiles without warnings
String s = stringLists[0].get(0); // Oh no, ClassCastException at runtime!
}
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
public Annotation[] getAnnotations() {}
@TestAnnotation()
public class Test {
public static void main(String[] args) {
boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
if ( hasAnnotation ) {
TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
System.out.println("id:"+testAnnotation.id());
System.out.println("msg:"+testAnnotation.msg());
}
}
}
/*
id:-1
msg:
*/
@TestAnnotation(msg="hello")
public class Test {
@Check(value="hi")
int a;
@Perform
public void testMethod(){}
@SuppressWarnings("deprecation")
public void test1(){
Hero hero = new Hero();
hero.say();
hero.speak();
}
public static void main(String[] args) {
boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
if ( hasAnnotation ) {
TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
//获取类的注解
System.out.println("id:"+testAnnotation.id());
System.out.println("msg:"+testAnnotation.msg());
}
try {
Field a = Test.class.getDeclaredField("a");
a.setAccessible(true);
//获取一个成员变量上的注解
Check check = a.getAnnotation(Check.class);
if ( check != null ) {
System.out.println("check value:"+check.value());
}
Method testMethod = Test.class.getDeclaredMethod("testMethod");
if ( testMethod != null ) {
// 获取方法中的注解
Annotation[] ans = testMethod.getAnnotations();
for( int i = 0;i < ans.length;i++) {
System.out.println("method testMethod annotation:"+ans[i].annotationType().getSimpleName());
}
}
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println(e.getMessage());
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println(e.getMessage());
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println(e.getMessage());
}
}
}
/*
id:-1
msg:hello
check value:hi
method testMethod annotation:Perform
*/