diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationManager.java index c77861678..7552b879e 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationManager.java @@ -30,6 +30,14 @@ import java.util.Map; public interface AuthenticationManager { String USER_AUTH_CACHE_NAME = "user-auth-"; + /** + * 进行授权操作 + * + * @param request 授权请求 + * @return 授权成功则返回用户权限信息 + */ + Authentication authenticate(AuthenticationRequest request); + /** * 根据用户ID获取权限信息 * diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationRequest.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationRequest.java new file mode 100644 index 000000000..78db8bfd8 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationRequest.java @@ -0,0 +1,10 @@ +package org.hswebframework.web.authorization; + +import java.io.Serializable; + +/** + * @author zhouhao + * @since 3.0.0-RC + */ +public interface AuthenticationRequest extends Serializable { +} diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/PlainTextUsernamePasswordAuthenticationRequest.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/PlainTextUsernamePasswordAuthenticationRequest.java new file mode 100644 index 000000000..7c857edf8 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/PlainTextUsernamePasswordAuthenticationRequest.java @@ -0,0 +1,21 @@ +package org.hswebframework.web.authorization.simple; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hswebframework.web.authorization.AuthenticationRequest; + +/** + * @author zhouhao + * @since 3.0.0-RC + */ +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class PlainTextUsernamePasswordAuthenticationRequest implements AuthenticationRequest { + private String username; + + private String password; +} diff --git a/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/AuthenticationTests.java b/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/AuthenticationTests.java index e03d75a6f..dac3632d9 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/AuthenticationTests.java +++ b/hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/AuthenticationTests.java @@ -1,12 +1,7 @@ package org.hswebframework.web.authorization; -import com.alibaba.fastjson.JSON; -import org.hswebframework.web.authorization.access.DataAccessConfig; -import org.hswebframework.web.authorization.access.FieldFilterDataAccessConfig; -import org.hswebframework.web.authorization.access.ScopeDataAccessConfig; import org.hswebframework.web.authorization.builder.AuthenticationBuilder; import org.hswebframework.web.authorization.exception.UnAuthorizedException; -import org.hswebframework.web.authorization.simple.SimpleFiledScopeDataAccessConfig; import org.hswebframework.web.authorization.simple.builder.SimpleAuthenticationBuilder; import org.hswebframework.web.authorization.simple.builder.SimpleDataAccessConfigBuilderFactory; import org.hswebframework.web.authorization.token.*; @@ -14,12 +9,9 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.Set; -import static org.hswebframework.web.authorization.Permission.scope; import static org.junit.Assert.*; public class AuthenticationTests { @@ -102,6 +94,11 @@ public class AuthenticationTests { //初始化权限管理器,用于获取用户的权限信息 AuthenticationManager authenticationManager = new AuthenticationManager() { + @Override + public Authentication authenticate(AuthenticationRequest request) { + return null; + } + @Override public Authentication getByUserId(String userId) { if (userId.equals("admin")) { diff --git a/hsweb-authorization/hsweb-authorization-basic/pom.xml b/hsweb-authorization/hsweb-authorization-basic/pom.xml index 18520420c..cd2ba8ce6 100644 --- a/hsweb-authorization/hsweb-authorization-basic/pom.xml +++ b/hsweb-authorization/hsweb-authorization-basic/pom.xml @@ -44,6 +44,34 @@ org.hswebframework hsweb-easy-orm-rdb + + + org.hswebframework.web + hsweb-spring-boot-starter + ${project.version} + test + + + + org.hswebframework.web + hsweb-tests + ${project.version} + test + + + + com.alibaba + druid + 1.0.26 + test + + + + com.h2database + h2 + test + + org.hswebframework.web hsweb-commons-controller diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/AuthorizingHandlerAutoConfiguration.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/AuthorizingHandlerAutoConfiguration.java index 2db8d96a2..7f1d8e9dd 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/AuthorizingHandlerAutoConfiguration.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/AuthorizingHandlerAutoConfiguration.java @@ -1,8 +1,10 @@ package org.hswebframework.web.authorization.basic.configuration; +import org.hswebframework.web.authorization.AuthenticationManager; import org.hswebframework.web.authorization.access.DataAccessController; import org.hswebframework.web.authorization.access.DataAccessHandler; import org.hswebframework.web.authorization.basic.aop.AopMethodAuthorizeDefinitionParser; +import org.hswebframework.web.authorization.basic.embed.EmbedAuthenticationManager; import org.hswebframework.web.authorization.basic.handler.DefaultAuthorizingHandler; import org.hswebframework.web.authorization.basic.handler.access.DefaultDataAccessController; import org.hswebframework.web.authorization.basic.web.*; @@ -11,6 +13,8 @@ import org.hswebframework.web.authorization.token.UserTokenManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; @@ -59,12 +63,18 @@ public class AuthorizingHandlerAutoConfiguration { return new WebMvcConfigurerAdapter() { @Override public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(new WebUserTokenInterceptor(userTokenManager, userTokenParser,parser)); + registry.addInterceptor(new WebUserTokenInterceptor(userTokenManager, userTokenParser, parser)); super.addInterceptors(registry); } }; } + @Bean + @ConditionalOnMissingBean(AuthenticationManager.class) + public AuthenticationManager embedAuthenticationManager() { + return new EmbedAuthenticationManager(); + } + @Bean public UserOnSignIn userOnSignIn(UserTokenManager userTokenManager) { return new UserOnSignIn(userTokenManager); diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedAuthenticationManager.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedAuthenticationManager.java new file mode 100644 index 000000000..86f34fd7d --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedAuthenticationManager.java @@ -0,0 +1,88 @@ +package org.hswebframework.web.authorization.basic.embed; + +import lombok.Getter; +import lombok.Setter; +import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.authorization.AuthenticationManager; +import org.hswebframework.web.authorization.AuthenticationRequest; +import org.hswebframework.web.authorization.builder.DataAccessConfigBuilderFactory; +import org.hswebframework.web.authorization.simple.PlainTextUsernamePasswordAuthenticationRequest; +import org.hswebframework.web.authorization.simple.builder.SimpleDataAccessConfigBuilderFactory; +import org.hswebframework.web.validate.ValidationException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.util.StringUtils; + +import javax.annotation.PostConstruct; +import java.util.HashMap; +import java.util.Map; + +/** + * @author zhouhao + * @since 3.0.0-RC + */ +@ConfigurationProperties(prefix = "hsweb") +public class EmbedAuthenticationManager implements AuthenticationManager { + + private Map authentications = new HashMap<>(); + + @Autowired(required = false) + private DataAccessConfigBuilderFactory dataAccessConfigBuilderFactory = new SimpleDataAccessConfigBuilderFactory(); + + @Getter + @Setter + private Map users = new HashMap<>(); + + @PostConstruct + public void init() { + users.forEach((id, properties) -> { + if (StringUtils.isEmpty(properties.getId())) { + properties.setId(id); + } + for (EmbedAuthenticationProperties.PermissionInfo permissionInfo : properties.getPermissions()) { + for (Map objectMap : permissionInfo.getDataAccesses()) { + for (Map.Entry stringObjectEntry : objectMap.entrySet()) { + if (stringObjectEntry.getValue() instanceof Map) { + Map mapVal = ((Map) stringObjectEntry.getValue()); + boolean maybeIsList = mapVal.keySet().stream().allMatch(org.hswebframework.utils.StringUtils::isInt); + if (maybeIsList) { + stringObjectEntry.setValue(mapVal.values()); + } + } + } + } + } + }); + } + + @Override + public Authentication authenticate(AuthenticationRequest request) { + if (request instanceof PlainTextUsernamePasswordAuthenticationRequest) { + return sync(users.values().stream() + .filter(user -> + ((PlainTextUsernamePasswordAuthenticationRequest) request).getUsername().equals(user.getUsername()) + && ((PlainTextUsernamePasswordAuthenticationRequest) request).getPassword().equals(user.getPassword())) + .findFirst() + .map(properties -> properties.toAuthentication(dataAccessConfigBuilderFactory)) + .orElseThrow(() -> new ValidationException("用户不存在"))); + } + + throw new UnsupportedOperationException("不支持的授权类型:" + request); + + } + + @Override + public Authentication getByUserId(String userId) { + return authentications.get(userId); + } + + @Override + public Authentication sync(Authentication authentication) { + authentications.put(authentication.getUser().getId(), authentication); + return authentication; + } + + void addAuthentication(Authentication authentication) { + sync(authentication); + } +} diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedAuthenticationProperties.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedAuthenticationProperties.java new file mode 100644 index 000000000..28bc188b8 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedAuthenticationProperties.java @@ -0,0 +1,97 @@ +package org.hswebframework.web.authorization.basic.embed; + +import com.alibaba.fastjson.JSON; +import lombok.Getter; +import lombok.Setter; +import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.authorization.Permission; +import org.hswebframework.web.authorization.Role; +import org.hswebframework.web.authorization.builder.DataAccessConfigBuilderFactory; +import org.hswebframework.web.authorization.simple.SimpleAuthentication; +import org.hswebframework.web.authorization.simple.SimplePermission; +import org.hswebframework.web.authorization.simple.SimpleRole; +import org.hswebframework.web.authorization.simple.SimpleUser; + +import java.util.*; +import java.util.stream.Collectors; + +/** + *
+ * hsweb:
+ *      users:
+ *          admin:
+ *            name: 超级管理员
+ *            username: admin
+ *            password: admin
+ *            roles:
+ *              - id: admin
+ *                name: 管理员
+ *              - id: user
+ *                name: 用户
+ *            permissions:
+ *              - id: user-manager
+ *                actions: *
+ *                dataAccesses:
+ *                  - action: query
+ *                    type: DENY_FIELDS
+ *                    fields: password,salt
+ * 
+ * + * @author zhouhao + * @since 3.0.0-RC + */ +@Getter +@Setter +public class EmbedAuthenticationProperties { + + private String id; + + private String name; + + private String username; + + private String type; + + private String password; + + private List roles = new ArrayList<>(); + + private List permissions = new ArrayList<>(); + + @Getter + @Setter + public static class PermissionInfo { + private String id; + + private Set actions = new HashSet<>(); + + private List> dataAccesses = new ArrayList<>(); + } + + public Authentication toAuthentication(DataAccessConfigBuilderFactory factory) { + SimpleAuthentication authentication = new SimpleAuthentication(); + SimpleUser user = new SimpleUser(); + user.setId(id); + user.setName(name); + user.setUsername(username); + user.setType(type); + authentication.setUser(user); + authentication.setRoles((List) roles); + List permissionList = permissions.stream() + .map(info -> { + SimplePermission permission = new SimplePermission(); + permission.setId(info.getId()); + permission.setActions(info.getActions()); + permission.setDataAccesses(info.getDataAccesses() + .stream().map(conf -> factory.create() + .fromJson(JSON.toJSONString(conf)) + .build()).collect(Collectors.toSet())); + return permission; + + }).collect(Collectors.toList()); + + authentication.setPermissions(permissionList); + return authentication; + } + +} diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/handler/DefaultAuthorizingHandler.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/handler/DefaultAuthorizingHandler.java index a4ed3d194..7c14b5c4e 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/handler/DefaultAuthorizingHandler.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/handler/DefaultAuthorizingHandler.java @@ -1,6 +1,7 @@ package org.hswebframework.web.authorization.basic.handler; import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.collections.CollectionUtils; import org.hswebframework.expands.script.engine.DynamicScriptEngine; import org.hswebframework.expands.script.engine.DynamicScriptEngineFactory; import org.hswebframework.web.authorization.Authentication; @@ -54,7 +55,7 @@ public class DefaultAuthorizingHandler implements AuthorizingHandler { @Override public void handRBAC(AuthorizingContext context) { - if(handleEvent(context,HandleType.RBAC)){ + if (handleEvent(context, HandleType.RBAC)) { return; } //进行rdac权限控制 @@ -63,8 +64,9 @@ public class DefaultAuthorizingHandler implements AuthorizingHandler { handleExpression(context.getAuthentication(), context.getDefinition(), context.getParamContext()); } - private boolean handleEvent(AuthorizingContext context,HandleType type){ - if(null!=eventPublisher) { + + private boolean handleEvent(AuthorizingContext context, HandleType type) { + if (null != eventPublisher) { AuthorizingHandleBeforeEvent event = new AuthorizingHandleBeforeEvent(context, type); eventPublisher.publishEvent(event); if (!event.isExecute()) { @@ -77,16 +79,17 @@ public class DefaultAuthorizingHandler implements AuthorizingHandler { } return false; } + public void handleDataAccess(AuthorizingContext context) { if (dataAccessController == null) { logger.warn("dataAccessController is null,skip result access control!"); return; } - if(context.getDefinition().getDataAccessDefinition()==null){ + if (context.getDefinition().getDataAccessDefinition() == null) { return; } - if(handleEvent(context,HandleType.DATA)){ + if (handleEvent(context, HandleType.DATA)) { return; } @@ -160,7 +163,7 @@ public class DefaultAuthorizingHandler implements AuthorizingHandler { logger.info("do permission access handle : permissions{}({}),actions{} ,definition:{}.{} ({})", definition.getPermissionDescription(), permissionsDef, actionsDef - ,definition.getPermissions(), + , definition.getPermissions(), definition.getActions(), definition.getLogical()); } @@ -188,14 +191,14 @@ public class DefaultAuthorizingHandler implements AuthorizingHandler { return logicalIsOr || permission.getActions().containsAll(actions); }).collect(Collectors.toList()); access = logicalIsOr ? - permissions.size() > 0 : + CollectionUtils.isNotEmpty(permissions) : //权限数量和配置的数量相同 permissions.size() == permissionsDef.size(); } //控制角色 if (!rolesDef.isEmpty()) { if (logger.isInfoEnabled()) { - logger.info("do role access handle : roles{} , definition:{}", rolesDef,definition.getRoles()); + logger.info("do role access handle : roles{} , definition:{}", rolesDef, definition.getRoles()); } Function, Boolean> func = logicalIsOr ? authentication.getRoles().stream()::anyMatch @@ -205,7 +208,7 @@ public class DefaultAuthorizingHandler implements AuthorizingHandler { //控制用户 if (!usersDef.isEmpty()) { if (logger.isInfoEnabled()) { - logger.info("do user access handle : users{} , definition:{} ", usersDef,definition.getUser()); + logger.info("do user access handle : users{} , definition:{} ", usersDef, definition.getUser()); } Function, Boolean> func = logicalIsOr ? usersDef.stream()::anyMatch diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-web/src/main/java/org/hswebframework/web/authorization/controller/AuthorizationController.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizationController.java similarity index 83% rename from hsweb-system/hsweb-system-authorization/hsweb-system-authorization-web/src/main/java/org/hswebframework/web/authorization/controller/AuthorizationController.java rename to hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizationController.java index 88236713b..7282a1dfc 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-web/src/main/java/org/hswebframework/web/authorization/controller/AuthorizationController.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizationController.java @@ -15,7 +15,7 @@ * */ -package org.hswebframework.web.authorization.controller; +package org.hswebframework.web.authorization.basic.web; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -26,12 +26,9 @@ import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.authorization.AuthenticationManager; import org.hswebframework.web.authorization.annotation.Authorize; import org.hswebframework.web.authorization.listener.event.*; -import org.hswebframework.web.commons.entity.DataStatus; +import org.hswebframework.web.authorization.simple.PlainTextUsernamePasswordAuthenticationRequest; import org.hswebframework.web.controller.message.ResponseMessage; -import org.hswebframework.web.entity.authorization.UserEntity; import org.hswebframework.web.logging.AccessLogger; -import org.hswebframework.web.service.authorization.UserService; -import org.hswebframework.web.validate.ValidationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.http.MediaType; @@ -53,9 +50,6 @@ import static org.hswebframework.web.controller.message.ResponseMessage.ok; @Api(tags = "权限-用户授权", value = "授权") public class AuthorizationController { - @Autowired - private UserService userService; - @Autowired private AuthenticationManager authenticationManager; @@ -108,20 +102,11 @@ public class AuthorizationController { password = decodeEvent.getPassword(); AuthorizationBeforeEvent beforeEvent = new AuthorizationBeforeEvent(username, password, parameterGetter); eventPublisher.publishEvent(beforeEvent); - UserEntity entity = userService.selectByUserNameAndPassword(username, password); - if (entity == null) { - reason = AuthorizationFailedEvent.Reason.PASSWORD_ERROR; - throw new ValidationException("密码错误", "password"); - } - if (!DataStatus.STATUS_ENABLED.equals(entity.getStatus())) { - reason = AuthorizationFailedEvent.Reason.USER_DISABLED; - throw new ValidationException("用户已被禁用", "username"); - } // 验证通过 - Authentication authentication = authenticationManager.getByUserId(entity.getId()); + Authentication authentication = authenticationManager.authenticate(new PlainTextUsernamePasswordAuthenticationRequest(username, password)); //触发授权成功事件 AuthorizationSuccessEvent event = new AuthorizationSuccessEvent(authentication, parameterGetter); - event.getResult().put("userId", entity.getId()); + event.getResult().put("userId", authentication.getUser().getId()); eventPublisher.publishEvent(event); return ok(event.getResult()); } catch (Exception e) { diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-web/src/main/java/org/hswebframework/web/authorization/controller/UserTokenController.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/UserTokenController.java similarity index 99% rename from hsweb-system/hsweb-system-authorization/hsweb-system-authorization-web/src/main/java/org/hswebframework/web/authorization/controller/UserTokenController.java rename to hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/UserTokenController.java index 1bc04061b..faa72f5b9 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-web/src/main/java/org/hswebframework/web/authorization/controller/UserTokenController.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/UserTokenController.java @@ -1,4 +1,4 @@ -package org.hswebframework.web.authorization.controller; +package org.hswebframework.web.authorization.basic.web; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; diff --git a/hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/embed/EmbedAuthenticationManagerTest.groovy b/hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/embed/EmbedAuthenticationManagerTest.groovy new file mode 100644 index 000000000..39921eab4 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/embed/EmbedAuthenticationManagerTest.groovy @@ -0,0 +1,40 @@ +package org.hswebframework.web.authorization.basic.embed + +import org.hswebframework.web.authorization.Authentication +import org.hswebframework.web.authorization.AuthenticationManager +import org.hswebframework.web.authorization.simple.PlainTextUsernamePasswordAuthenticationRequest +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.web.WebAppConfiguration +import spock.lang.Specification + +/** + * @author zhouhao + * @since 3.0.0-RC + */ +@WebAppConfiguration +@ContextConfiguration +@SpringBootTest(classes = [TestApplication.class], properties = ["classpath:application.yml"]) +class EmbedAuthenticationManagerTest extends Specification { + + @Autowired + private AuthenticationManager manager; + + + def "Test"() { + setup: + Authentication authentication = manager.authenticate(new PlainTextUsernamePasswordAuthenticationRequest("admin", "admin")); + expect: + authentication != null + authentication.getUser() != null + authentication.getUser().getName() == "超级管理员" + authentication.hasPermission("user-manager", "query") + authentication.getPermission("user-manager") != null + authentication.hasRole("user") + authentication.getPermission("user-manager") + .get().findDenyFields("query") != null + authentication.getPermission("user-manager") + .get().findDenyFields("query").contains("password") + } +} diff --git a/hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/embed/TestApplication.java b/hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/embed/TestApplication.java new file mode 100644 index 000000000..c5b2310a7 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/embed/TestApplication.java @@ -0,0 +1,19 @@ +package org.hswebframework.web.authorization.basic.embed; + +import org.hswebframework.web.authorization.basic.configuration.AopAuthorizeAutoConfiguration; +import org.hswebframework.web.authorization.basic.configuration.AuthorizingHandlerAutoConfiguration; +import org.hswebframework.web.authorization.basic.configuration.EnableAopAuthorize; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.test.context.web.WebAppConfiguration; + +/** + * @author zhouhao + * @since 3.0.0-RC + */ +@SpringBootApplication +@WebAppConfiguration +@EnableAopAuthorize +public class TestApplication { + +} diff --git a/hsweb-authorization/hsweb-authorization-basic/src/test/resources/application.yml b/hsweb-authorization/hsweb-authorization-basic/src/test/resources/application.yml new file mode 100644 index 000000000..6a69af19a --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-basic/src/test/resources/application.yml @@ -0,0 +1,38 @@ + +spring: + aop: + auto: true + proxy-target-class: true + datasource: + url : jdbc:h2:mem:example-oauth2-client + username : sa + password : + type: com.alibaba.druid.pool.DruidDataSource + driver-class-name : org.h2.Driver + cache: + type: simple +hsweb: + app: + name: hsweb-oauth2 客户端示例 + version: 3.0.0 + users: + admin: + name: 超级管理员 + username: admin + password: admin + roles: #用户的角色 + - id: admin + name: 管理员 + - id: user + name: 用户 + permissions: + - id: user-manager + actions: query,get,update,delete + dataAccesses: + - action: query + type: DENY_FIELDS + fields: + - password + - salt +server: + port: 8808 diff --git a/hsweb-examples/hsweb-examples-oauth2/hsweb-examples-oauth2-client/src/main/java/org/hswebframework/web/example/oauth2/MemoryAuthenticationManager.java b/hsweb-examples/hsweb-examples-oauth2/hsweb-examples-oauth2-client/src/main/java/org/hswebframework/web/example/oauth2/MemoryAuthenticationManager.java index 45616d70b..023aa70c7 100644 --- a/hsweb-examples/hsweb-examples-oauth2/hsweb-examples-oauth2-client/src/main/java/org/hswebframework/web/example/oauth2/MemoryAuthenticationManager.java +++ b/hsweb-examples/hsweb-examples-oauth2/hsweb-examples-oauth2-client/src/main/java/org/hswebframework/web/example/oauth2/MemoryAuthenticationManager.java @@ -2,6 +2,7 @@ package org.hswebframework.web.example.oauth2; import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.authorization.AuthenticationManager; +import org.hswebframework.web.authorization.AuthenticationRequest; import java.util.HashMap; import java.util.Map; @@ -13,6 +14,11 @@ public class MemoryAuthenticationManager implements AuthenticationManager { users.put(authentication.getUser().getId(), authentication); } + @Override + public Authentication authenticate(AuthenticationRequest request) { + return null; + } + @Override public Authentication getByUserId(String userId) { diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-local/src/main/java/org/hswebframework/web/service/authorization/simple/SimpleAuthenticationManager.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-local/src/main/java/org/hswebframework/web/service/authorization/simple/SimpleAuthenticationManager.java index 597c2debd..68465740f 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-local/src/main/java/org/hswebframework/web/service/authorization/simple/SimpleAuthenticationManager.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-local/src/main/java/org/hswebframework/web/service/authorization/simple/SimpleAuthenticationManager.java @@ -3,10 +3,21 @@ package org.hswebframework.web.service.authorization.simple; import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.authorization.AuthenticationInitializeService; import org.hswebframework.web.authorization.AuthenticationManager; +import org.hswebframework.web.authorization.AuthenticationRequest; +import org.hswebframework.web.authorization.listener.event.AuthorizationFailedEvent; +import org.hswebframework.web.authorization.simple.PlainTextUsernamePasswordAuthenticationRequest; +import org.hswebframework.web.commons.entity.DataStatus; +import org.hswebframework.web.entity.authorization.UserEntity; +import org.hswebframework.web.service.authorization.UserService; +import org.hswebframework.web.validate.ValidationException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; +import java.util.function.Supplier; + /** * @author zhouhao */ @@ -14,6 +25,12 @@ public class SimpleAuthenticationManager implements AuthenticationManager { private AuthenticationInitializeService authenticationInitializeService; + @Autowired + private UserService userService; + + @Autowired(required = false) + private CacheManager cacheManager; + public SimpleAuthenticationManager() { } @@ -27,9 +44,39 @@ public class SimpleAuthenticationManager implements AuthenticationManager { } @Override - @Cacheable(value = USER_AUTH_CACHE_NAME, key = "#userId") + public Authentication authenticate(AuthenticationRequest request) { + if (request instanceof PlainTextUsernamePasswordAuthenticationRequest) { + String username = ((PlainTextUsernamePasswordAuthenticationRequest) request).getUsername(); + String password = ((PlainTextUsernamePasswordAuthenticationRequest) request).getPassword(); + UserEntity userEntity = userService.selectByUserNameAndPassword(username, password); + if (userEntity == null) { + throw new ValidationException("密码错误", "password"); + } + if (!DataStatus.STATUS_ENABLED.equals(userEntity.getStatus())) { + throw new ValidationException("用户已被禁用", "username"); + } + return getByUserId(userEntity.getId()); + } + return null; + } + + @Override +// @Cacheable(value = USER_AUTH_CACHE_NAME, key = "#userId") public Authentication getByUserId(String userId) { - return authenticationInitializeService.initUserAuthorization(userId); + Supplier supplier = () -> authenticationInitializeService.initUserAuthorization(userId); + + if (null != cacheManager) { + Cache cache = cacheManager.getCache(USER_AUTH_CACHE_NAME); + Cache.ValueWrapper wrapper = cache.get(userId); + if (wrapper == null) { + Authentication authentication = supplier.get(); + cache.put(userId, authentication); + return authentication; + } else { + return (Authentication) wrapper.get(); + } + } + return supplier.get(); } @Override diff --git a/quick-start/README.md b/quick-start/README.md index 4c53007f7..0a94e52c5 100644 --- a/quick-start/README.md +++ b/quick-start/README.md @@ -291,4 +291,26 @@ public class MyProjectApplication { 以权限管理模块(`hsweb-system/hsweb-system-authorization`)为例. -TODO \ No newline at end of file +在pom.xml中引入模块: +```xml + + + org.hswebframework.web + hsweb-authorization-basic + ${hsweb.framework.version} + + + + + org.hswebframework.web + hsweb-system-authorization-starter + ${hsweb.framework.version} + +``` + +![import-authorization-module](./img/import-authorization-module.gif "import-authorization-module") + + + + +