增加AuthorizationListener

This commit is contained in:
zhouhao
2017-03-04 14:15:27 +08:00
parent 26ad72b1b3
commit 89b2c43359
16 changed files with 485 additions and 85 deletions

View File

@@ -23,3 +23,32 @@ _点击名称,查看源代码注释获得使用说明_
| ------------- |:-------------:|
| [`Authorization`](src/main/java/org/hswebframework/web/authorization/Authorization.java) | 用户的认证信息 |
| [`AuthorizationHolder`](src/main/java/org/hswebframework/web/authorization/AuthorizationHolder.java) | 用于获取当前登录用户的认证信息 |
### Listener
api提供[AuthorizationListener](src/main/java/org/hswebframework/web/authorization/listener/AuthorizationListener.java)
来进行授权逻辑拓展,在授权前后执行可自定义的操作.如rsa解密帐号密码,验证码判断等。
默认事件列表():
| 类名 | 说明 |
| ------------- |:-------------:|
| [`AuthorizationDecodeEvent`](src/main/java/org/hswebframework/web/authorization/listener/event/AuthorizationDecodeEvent.java) | 接收到请求参数时 |
| [`AuthorizationBeforeEvent`](src/main/java/org/hswebframework/web/authorization/listener/event/AuthorizationBeforeEvent.java) | 验证密码前触发 |
| [`AuthorizationFailedEvent`](src/main/java/org/hswebframework/web/authorization/listener/event/AuthorizationFailedEvent.java) | 授权验证失败时触发 |
| [`AuthorizationSuccessEvent`](src/main/java/org/hswebframework/web/authorization/listener/event/AuthorizationSuccessEvent.java) | 授权成功时触发 |
| [`AuthorizationExitEvent`](src/main/java/org/hswebframework/web/authorization/listener/event/AuthorizationExitEvent.java) | 用户注销时触发 |
例子:
```java
@Component
public class CustomAuthorizationSuccessListener implements AuthorizationListener<AuthorizationSuccessEvent>{
@Override
public void on(AuthorizationSuccessEvent event) {
Authorization authorization=event.getAuthorization();
//....
System.out.println(authorization.getUser().getName()+"登录啦");
}
}
```

View File

@@ -11,5 +11,4 @@
<artifactId>hsweb-authorization-api</artifactId>
</project>

View File

@@ -0,0 +1,16 @@
package org.hswebframework.web.authorization.listener;
import org.hswebframework.web.authorization.listener.event.AuthorizationEvent;
/**
* 授权监听器,用于监听授权过程,以及自定义授权逻辑
*
* @author zhouhao
* @see AuthorizationEvent
* @since 3.0
*/
public interface AuthorizationListener<E extends AuthorizationEvent> {
void on(E event);
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright 2016 http://www.hswebframework.org
*
* Licensed 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.
*
*
*/
package org.hswebframework.web.authorization.listener;
import org.hswebframework.web.authorization.listener.event.AuthorizationEvent;
import java.util.*;
/**
* @author zhouhao
*/
public class AuthorizationListenerDispatcher {
private Map<Class<? extends AuthorizationEvent>, List<AuthorizationListener>> listenerStore = new HashMap<>();
public <E extends AuthorizationEvent> void addListener(Class<E> eventClass, AuthorizationListener<E> listener) {
listenerStore.computeIfAbsent(eventClass, (k) -> new LinkedList<>())
.add(listener);
}
@SuppressWarnings("unchecked")
public <E extends AuthorizationEvent> void doEvent(Class<E> eventType, E event) {
List<AuthorizationListener<E>> store = (List) listenerStore.get(eventType);
if (null != store) {
store.forEach(listener -> listener.on(event));
}
}
@SuppressWarnings("unchecked")
public <E extends AuthorizationEvent> void doEvent(E event) {
doEvent((Class<E>) event.getClass(), event);
}
}

View File

@@ -1,27 +0,0 @@
/*
* Copyright 2016 http://www.hswebframework.org
*
* Licensed 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.
*
*/
package org.hswebframework.web.authorization.listener;
/**
* TODO 完成注释
*
* @author zhouhao
*/
public interface UserAuthorizationConfigRegister {
void setUseVerifyCode(boolean useVerifyCode);
}

View File

@@ -1,43 +0,0 @@
/*
* Copyright 2016 http://www.hswebframework.org
*
* Licensed 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.
*
*/
package org.hswebframework.web.authorization.listener;
import org.hswebframework.web.authorization.Authorization;
/**
* TODO 完成注释
*
* @author zhouhao
*/
public interface UserAuthorizationListener {
default void onConfig(String username, UserAuthorizationConfigRegister configHolder) {
}
default void onAuthorizeBefore(String username) {
}
default void onAuthorizeFail(String username) {
}
default void onLoginOut(Authorization authorization){
}
void onAuthorizeSuccess(boolean isRemembered, Authorization authorization);
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2016 http://www.hswebframework.org
*
* Licensed 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.
*
*
*/
package org.hswebframework.web.authorization.listener.event;
import java.util.Optional;
import java.util.function.Function;
/**
* 抽象授权事件,保存事件常用的数据
*
* @author zhouhao
* @since 3.0
*/
public abstract class AbstractAuthorizationEvent implements AuthorizationEvent {
protected String username;
protected String password;
private Function<String, Object> parameterGetter;
/**
* 带参构造方法,所有参数不能为null
*
* @param username 用户名
* @param password 密码
* @param parameterGetter 参数获取函数,用户获取授权时传入的参数
*/
public AbstractAuthorizationEvent(String username, String password, Function<String, Object> parameterGetter) {
if (username == null || password == null || parameterGetter == null) throw new NullPointerException();
this.username = username;
this.password = password;
this.parameterGetter = parameterGetter;
}
@SuppressWarnings("unchecked")
protected <T> Optional<T> getParameter(String name) {
return Optional.ofNullable((T) parameterGetter.apply(name));
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2016 http://www.hswebframework.org
*
* Licensed 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.
*
*
*/
package org.hswebframework.web.authorization.listener.event;
import java.util.function.Function;
/**
* 授权前事件
*
* @author zhouhao
* @since 3.0
*/
public class AuthorizationBeforeEvent extends AbstractAuthorizationEvent {
public AuthorizationBeforeEvent(String username, String password, Function<String, Object> parameterGetter) {
super(username, password, parameterGetter);
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2016 http://www.hswebframework.org
*
* Licensed 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.
*
*
*/
package org.hswebframework.web.authorization.listener.event;
import java.util.function.Function;
/**
* 在进行授权时的最开始,触发此事件进行用户名密码解码,解码后请调用{@link #setUsername(String)} {@link #setPassword(String)}重新设置用户名密码
*
* @author zhouhao
* @since 3.0
*/
public class AuthorizationDecodeEvent extends AbstractAuthorizationEvent {
public AuthorizationDecodeEvent(String username, String password, Function<String, Object> parameterGetter) {
super(username, password, parameterGetter);
}
public void setUsername(String username) {
super.username = username;
}
public void setPassword(String password) {
super.username = password;
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2016 http://www.hswebframework.org
*
* Licensed 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.
*
*
*/
package org.hswebframework.web.authorization.listener.event;
/**
* 授权事件
*
* @author zhouhao
* @see AuthorizationSuccessEvent
* @see AuthorizationFailedEvent
* @see AuthorizationBeforeEvent
* @see AuthorizationDecodeEvent
* @see AuthorizationExitEvent
* @since 3.0
*/
public interface AuthorizationEvent {
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2016 http://www.hswebframework.org
*
* Licensed 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.
*
*
*/
package org.hswebframework.web.authorization.listener.event;
import org.hswebframework.web.authorization.Authorization;
/**
* 退出登录事件
*
* @author zhouhao
*/
public class AuthorizationExitEvent implements AuthorizationEvent {
private Authorization authorization;
public AuthorizationExitEvent(Authorization authorization) {
this.authorization = authorization;
}
public Authorization getAuthorization() {
return authorization;
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2016 http://www.hswebframework.org
*
* Licensed 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.
*
*
*/
package org.hswebframework.web.authorization.listener.event;
import java.util.function.Function;
/**
* 授权失败时触发
*
* @author zhouhao
*/
public class AuthorizationFailedEvent extends AbstractAuthorizationEvent {
/**
* 失败原因
*/
private Reason reason;
/**
* 异常信息
*/
private Exception exception;
public AuthorizationFailedEvent(String username,
String password,
Function<String, Object> parameterGetter,
Reason reason) {
super(username, password, parameterGetter);
this.reason = reason;
}
public Exception getException() {
return exception;
}
public void setException(Exception exception) {
this.exception = exception;
}
public Reason getReason() {
return reason;
}
public enum Reason {
PASSWORD_ERROR, USER_DISABLED, USER_NOT_EXISTS, OTHER
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2016 http://www.hswebframework.org
*
* Licensed 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.
*
*
*/
package org.hswebframework.web.authorization.listener.event;
import org.hswebframework.web.authorization.Authorization;
import java.util.Optional;
import java.util.function.Function;
/**
* 授权成功事件,当授权成功时,触发此事件,并传入授权的信息
*
* @author zhouhao
* @see Authorization
* @since 3.0
*/
public class AuthorizationSuccessEvent implements AuthorizationEvent {
private Authorization authorization;
private Function<String,Object> parameterGetter;
public AuthorizationSuccessEvent(Authorization authorization, Function<String, Object> parameterGetter) {
this.authorization = authorization;
this.parameterGetter = parameterGetter;
}
public Authorization getAuthorization() {
return authorization;
}
@SuppressWarnings("unchecked")
public <T> Optional<T> getParameter(String name) {
return Optional.ofNullable((T) parameterGetter.apply(name));
}
}

View File

@@ -31,14 +31,16 @@ import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.hswebframework.web.authorization.Authorization;
import org.hswebframework.web.authorization.Role;
import org.hswebframework.web.authorization.listener.UserAuthorizationListener;
import org.hswebframework.web.authorization.listener.AuthorizationListener;
import org.hswebframework.web.authorization.listener.event.AuthorizationSuccessEvent;
import java.util.stream.Collectors;
/**
* @author zhouhao
*/
public class ListenerAuthorizingRealm extends AuthorizingRealm implements UserAuthorizationListener {
public class ListenerAuthorizingRealm extends AuthorizingRealm
implements AuthorizationListener<AuthorizationSuccessEvent> {
public ListenerAuthorizingRealm() {
setAuthenticationTokenClass(SimpleAuthenticationToken.class);
@@ -66,15 +68,25 @@ public class ListenerAuthorizingRealm extends AuthorizingRealm implements UserAu
authorization.getUser().getId(), ListenerAuthorizingRealm.class.getName());
}
@Override
public void onLoginOut(Authorization authorization) {
public void loginOut(Authorization authorization) {
if (null != authorization)
getCache(authorization.getUser().getUsername()).clear();
SecurityUtils.getSubject().logout();
}
protected <K, V> Cache<K, V> getCache(String name) {
return getCacheManager().getCache(getCacheName(name));
}
protected String getCacheName(String name) {
return "shiro.auth.info.".concat(name);
}
@Override
public void onAuthorizeSuccess(boolean isRemembered, Authorization authorization) {
public void on(AuthorizationSuccessEvent event) {
Authorization authorization = event.getAuthorization();
boolean remember = Boolean.TRUE.equals(event.getParameter("remember").orElse(false));
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.addRoles(authorization.getRoles().stream().map(Role::getId).collect(Collectors.toList()));
authorizationInfo.addObjectPermissions(
@@ -95,15 +107,7 @@ public class ListenerAuthorizingRealm extends AuthorizingRealm implements UserAu
.put(AuthenticationInfo.class.getName(), createAuthenticationInfo(authorization));
Subject subject = SecurityUtils.getSubject();
subject.login(new SimpleAuthenticationToken(authorization, isRemembered));
subject.login(new SimpleAuthenticationToken(authorization, remember));
subject.getSession().setAttribute(Authorization.class.getName(), authorization);
}
protected <K, V> Cache<K, V> getCache(String name) {
return getCacheManager().getCache(getCacheName(name));
}
protected String getCacheName(String name) {
return "shiro.auth.info.".concat(name);
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2016 http://www.hswebframework.org
*
* Licensed 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.
*
*
*/
package org.hswebframework.web.authorization.shiro;
import org.hswebframework.web.authorization.listener.AuthorizationListener;
import org.hswebframework.web.authorization.listener.event.AuthorizationExitEvent;
/**
*
* @author zhouhao
*/
public class LoginExitListener implements AuthorizationListener<AuthorizationExitEvent> {
private ListenerAuthorizingRealm listenerAuthorizingRealm;
public LoginExitListener(ListenerAuthorizingRealm listenerAuthorizingRealm) {
this.listenerAuthorizingRealm = listenerAuthorizingRealm;
}
@Override
public void on(AuthorizationExitEvent event) {
listenerAuthorizingRealm.loginOut(event.getAuthorization());
}
}

View File

@@ -94,12 +94,18 @@ public class ShiroAutoconfiguration {
}
@Bean
@Order(Ordered.LOWEST_PRECEDENCE)
public ListenerAuthorizingRealm listenerAuthorizingRealm(CacheManager cacheManager) {
ListenerAuthorizingRealm realm = new ListenerAuthorizingRealm();
realm.setCacheManager(cacheManager);
return realm;
}
@Bean
public LoginExitListener loginExitListener(ListenerAuthorizingRealm listenerAuthorizingRealm) {
return new LoginExitListener(listenerAuthorizingRealm);
}
@Bean(name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();