├── .gitignore ├── .mvn └── wrapper │ ├── MavenWrapperDownloader.java │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── HELP.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── ajax.http ├── csrf.http ├── java │ └── io │ │ └── security │ │ └── corespringsecurity │ │ ├── CoreSpringSecurityApplication.java │ │ ├── aopsecurity │ │ ├── AopLiveMethodService.java │ │ ├── AopMethodService.java │ │ ├── AopPointcutService.java │ │ └── AopSecurityController.java │ │ ├── controller │ │ ├── HomeController.java │ │ ├── admin │ │ │ ├── AdminController.java │ │ │ ├── ConfigController.java │ │ │ ├── ResourcesController.java │ │ │ ├── RoleController.java │ │ │ └── UserManagerController.java │ │ ├── login │ │ │ └── LoginController.java │ │ └── user │ │ │ ├── MessageController.java │ │ │ └── UserController.java │ │ ├── domain │ │ ├── dto │ │ │ ├── AccountDto.java │ │ │ ├── ResourcesDto.java │ │ │ └── RoleDto.java │ │ └── entity │ │ │ ├── AccessIp.java │ │ │ ├── Account.java │ │ │ ├── Resources.java │ │ │ ├── Role.java │ │ │ └── RoleHierarchy.java │ │ ├── repository │ │ ├── AccessIpRepository.java │ │ ├── ResourcesRepository.java │ │ ├── RoleHierarchyRepository.java │ │ ├── RoleRepository.java │ │ └── UserRepository.java │ │ ├── security │ │ ├── common │ │ │ ├── AjaxLoginAuthenticationEntryPoint.java │ │ │ ├── FormWebAuthenticationDetails.java │ │ │ └── FormWebAuthenticationDetailsSource.java │ │ ├── configs │ │ │ ├── AjaxLoginConfigurer.java │ │ │ ├── AjaxSecurityConfig.java │ │ │ ├── MethodSecurityConfig.java │ │ │ └── SecurityConfig.java │ │ ├── factory │ │ │ ├── MethodResourcesMapFactoryBean.java │ │ │ └── UrlResourcesMapFactoryBean.java │ │ ├── filter │ │ │ ├── AjaxLoginProcessingFilter.java │ │ │ └── PermitAllFilter.java │ │ ├── handler │ │ │ ├── AjaxAccessDeniedHandler.java │ │ │ ├── AjaxAuthenticationFailureHandler.java │ │ │ ├── AjaxAuthenticationSuccessHandler.java │ │ │ ├── FormAccessDeniedHandler.java │ │ │ ├── FormAuthenticationFailureHandler.java │ │ │ └── FormAuthenticationSuccessHandler.java │ │ ├── init │ │ │ └── SecurityInitializer.java │ │ ├── interceptor │ │ │ └── CustomMethodSecurityInterceptor.java │ │ ├── listener │ │ │ └── SetupDataLoader.java │ │ ├── metadatasource │ │ │ └── UrlFilterInvocationSecurityMetadataSource.java │ │ ├── processor │ │ │ └── ProtectPointcutPostProcessor.java │ │ ├── provider │ │ │ ├── AjaxAuthenticationProvider.java │ │ │ └── FormAuthenticationProvider.java │ │ ├── service │ │ │ ├── AccountContext.java │ │ │ └── UserDetailsServiceImpl.java │ │ ├── token │ │ │ └── AjaxAuthenticationToken.java │ │ └── voter │ │ │ └── IpAddressVoter.java │ │ ├── service │ │ ├── MethodSecurityService.java │ │ ├── ResourcesService.java │ │ ├── RoleHierarchyService.java │ │ ├── RoleService.java │ │ ├── SecurityResourceService.java │ │ ├── UserService.java │ │ └── impl │ │ │ ├── ResourcesServiceImpl.java │ │ │ ├── RoleHierarchyServiceImpl.java │ │ │ ├── RoleServiceImpl.java │ │ │ └── UserServiceImpl.java │ │ └── util │ │ └── WebUtil.java └── resources │ ├── application.properties │ ├── static │ ├── css │ │ ├── base.css │ │ ├── bootstrap-responsive.min.css │ │ ├── bootstrap-table.css │ │ ├── bootstrap.min.css │ │ └── style.css │ ├── images │ │ └── springsecurity.jpg │ └── js │ │ ├── bootstrap-table.js │ │ ├── bootstrap.min.js │ │ └── jquery-2.1.3.min.js │ └── templates │ ├── admin │ ├── common │ │ ├── head.html │ │ └── top.html │ ├── config.html │ ├── home.html │ ├── resource │ │ ├── detail.html │ │ └── list.html │ ├── role │ │ ├── detail.html │ │ └── list.html │ └── user │ │ ├── detail.html │ │ └── list.html │ ├── aop │ └── method.html │ ├── home.html │ ├── layout │ ├── footer.html │ ├── header.html │ └── top.html │ ├── login.html │ └── user │ ├── login │ ├── denied.html │ └── register.html │ ├── messages.html │ └── mypage.html └── test └── java └── io └── security └── corespringsecurity └── CorespringsecurityApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | target 3 | /logs 4 | /logs/ 5 | logs 6 | build 7 | !.mvn/wrapper/maven-wrapper.jar 8 | /src/main/resources/maxmind/ 9 | 10 | ### STS ### 11 | .apt_generated 12 | .classpath 13 | .factorypath 14 | .project 15 | .settings 16 | .springBeans 17 | .sts4-cache 18 | 19 | ### IntelliJ IDEA ### 20 | .idea 21 | *.iws 22 | *.iml 23 | *.ipr 24 | *.mmdb 25 | 26 | ### NetBeans ### 27 | /nbproject/private/ 28 | /build/ 29 | /nbbuild/ 30 | /dist/ 31 | /nbdist/ 32 | /.nb-gradle/ -------------------------------------------------------------------------------- /.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import java.net.*; 18 | import java.io.*; 19 | import java.nio.channels.*; 20 | import java.util.Properties; 21 | 22 | public class MavenWrapperDownloader { 23 | 24 | private static final String WRAPPER_VERSION = "0.5.5"; 25 | /** 26 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 27 | */ 28 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 29 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 30 | 31 | /** 32 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 33 | * use instead of the default one. 34 | */ 35 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 36 | ".mvn/wrapper/maven-wrapper.properties"; 37 | 38 | /** 39 | * Path where the maven-wrapper.jar will be saved to. 40 | */ 41 | private static final String MAVEN_WRAPPER_JAR_PATH = 42 | ".mvn/wrapper/maven-wrapper.jar"; 43 | 44 | /** 45 | * Name of the property which should be used to override the default download url for the wrapper. 46 | */ 47 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 48 | 49 | public static void main(String args[]) { 50 | System.out.println("- Downloader started"); 51 | File baseDirectory = new File(args[0]); 52 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 53 | 54 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 55 | // wrapperUrl parameter. 56 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 57 | String url = DEFAULT_DOWNLOAD_URL; 58 | if (mavenWrapperPropertyFile.exists()) { 59 | FileInputStream mavenWrapperPropertyFileInputStream = null; 60 | try { 61 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 62 | Properties mavenWrapperProperties = new Properties(); 63 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 64 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 65 | } catch (IOException e) { 66 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 67 | } finally { 68 | try { 69 | if (mavenWrapperPropertyFileInputStream != null) { 70 | mavenWrapperPropertyFileInputStream.close(); 71 | } 72 | } catch (IOException e) { 73 | // Ignore ... 74 | } 75 | } 76 | } 77 | System.out.println("- Downloading from: " + url); 78 | 79 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 80 | if (!outputFile.getParentFile().exists()) { 81 | if (!outputFile.getParentFile().mkdirs()) { 82 | System.out.println( 83 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 84 | } 85 | } 86 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 87 | try { 88 | downloadFileFromURL(url, outputFile); 89 | System.out.println("Done"); 90 | System.exit(0); 91 | } catch (Throwable e) { 92 | System.out.println("- Error downloading"); 93 | e.printStackTrace(); 94 | System.exit(1); 95 | } 96 | } 97 | 98 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 99 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 100 | String username = System.getenv("MVNW_USERNAME"); 101 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 102 | Authenticator.setDefault(new Authenticator() { 103 | @Override 104 | protected PasswordAuthentication getPasswordAuthentication() { 105 | return new PasswordAuthentication(username, password); 106 | } 107 | }); 108 | } 109 | URL website = new URL(urlString); 110 | ReadableByteChannel rbc; 111 | rbc = Channels.newChannel(website.openStream()); 112 | FileOutputStream fos = new FileOutputStream(destination); 113 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 114 | fos.close(); 115 | rbc.close(); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onjsdnjs/corespringsecurityfinal/eec4b30d8cc7157f347ef948c136a58fd1cbb284/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /HELP.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ### Reference Documentation 4 | For further reference, please consider the following sections: 5 | 6 | * [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) 7 | * [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.2.1.RELEASE/maven-plugin/) 8 | * [Spring Security](https://docs.spring.io/spring-boot/docs/2.2.1.RELEASE/reference/htmlsingle/#boot-features-security) 9 | * [Spring Configuration Processor](https://docs.spring.io/spring-boot/docs/2.2.1.RELEASE/reference/htmlsingle/#configuration-metadata-annotation-processor) 10 | * [Spring Web](https://docs.spring.io/spring-boot/docs/2.2.1.RELEASE/reference/htmlsingle/#boot-features-developing-web-applications) 11 | * [Spring Data JPA](https://docs.spring.io/spring-boot/docs/2.2.1.RELEASE/reference/htmlsingle/#boot-features-jpa-and-spring-data) 12 | * [Spring Boot DevTools](https://docs.spring.io/spring-boot/docs/2.2.1.RELEASE/reference/htmlsingle/#using-boot-devtools) 13 | * [Thymeleaf](https://docs.spring.io/spring-boot/docs/2.2.1.RELEASE/reference/htmlsingle/#boot-features-spring-mvc-template-engines) 14 | 15 | ### Guides 16 | The following guides illustrate how to use some features concretely: 17 | 18 | * [Securing a Web Application](https://spring.io/guides/gs/securing-web/) 19 | * [Spring Boot and OAuth2](https://spring.io/guides/tutorials/spring-boot-oauth2/) 20 | * [Authenticating a User with LDAP](https://spring.io/guides/gs/authenticating-ldap/) 21 | * [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/) 22 | * [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/) 23 | * [Building REST services with Spring](https://spring.io/guides/tutorials/bookmarks/) 24 | * [Accessing Data with JPA](https://spring.io/guides/gs/accessing-data-jpa/) 25 | * [Handling Form Submission](https://spring.io/guides/gs/handling-form-submission/) 26 | 27 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Mingw, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | fi 118 | 119 | if [ -z "$JAVA_HOME" ]; then 120 | javaExecutable="`which javac`" 121 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 122 | # readlink(1) is not available as standard on Solaris 10. 123 | readLink=`which readlink` 124 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 125 | if $darwin ; then 126 | javaHome="`dirname \"$javaExecutable\"`" 127 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 128 | else 129 | javaExecutable="`readlink -f \"$javaExecutable\"`" 130 | fi 131 | javaHome="`dirname \"$javaExecutable\"`" 132 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 133 | JAVA_HOME="$javaHome" 134 | export JAVA_HOME 135 | fi 136 | fi 137 | fi 138 | 139 | if [ -z "$JAVACMD" ] ; then 140 | if [ -n "$JAVA_HOME" ] ; then 141 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 142 | # IBM's JDK on AIX uses strange locations for the executables 143 | JAVACMD="$JAVA_HOME/jre/sh/java" 144 | else 145 | JAVACMD="$JAVA_HOME/bin/java" 146 | fi 147 | else 148 | JAVACMD="`which java`" 149 | fi 150 | fi 151 | 152 | if [ ! -x "$JAVACMD" ] ; then 153 | echo "Error: JAVA_HOME is not defined correctly." >&2 154 | echo " We cannot execute $JAVACMD" >&2 155 | exit 1 156 | fi 157 | 158 | if [ -z "$JAVA_HOME" ] ; then 159 | echo "Warning: JAVA_HOME environment variable is not set." 160 | fi 161 | 162 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 163 | 164 | # traverses directory structure from process work directory to filesystem root 165 | # first directory with .mvn subdirectory is considered project base directory 166 | find_maven_basedir() { 167 | 168 | if [ -z "$1" ] 169 | then 170 | echo "Path not specified to find_maven_basedir" 171 | return 1 172 | fi 173 | 174 | basedir="$1" 175 | wdir="$1" 176 | while [ "$wdir" != '/' ] ; do 177 | if [ -d "$wdir"/.mvn ] ; then 178 | basedir=$wdir 179 | break 180 | fi 181 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 182 | if [ -d "${wdir}" ]; then 183 | wdir=`cd "$wdir/.."; pwd` 184 | fi 185 | # end of workaround 186 | done 187 | echo "${basedir}" 188 | } 189 | 190 | # concatenates all lines of a file 191 | concat_lines() { 192 | if [ -f "$1" ]; then 193 | echo "$(tr -s '\n' ' ' < "$1")" 194 | fi 195 | } 196 | 197 | BASE_DIR=`find_maven_basedir "$(pwd)"` 198 | if [ -z "$BASE_DIR" ]; then 199 | exit 1; 200 | fi 201 | 202 | ########################################################################################## 203 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 204 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 205 | ########################################################################################## 206 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 207 | if [ "$MVNW_VERBOSE" = true ]; then 208 | echo "Found .mvn/wrapper/maven-wrapper.jar" 209 | fi 210 | else 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 213 | fi 214 | if [ -n "$MVNW_REPOURL" ]; then 215 | jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" 216 | else 217 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" 218 | fi 219 | while IFS="=" read key value; do 220 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 221 | esac 222 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 223 | if [ "$MVNW_VERBOSE" = true ]; then 224 | echo "Downloading from: $jarUrl" 225 | fi 226 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 227 | if $cygwin; then 228 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 229 | fi 230 | 231 | if command -v wget > /dev/null; then 232 | if [ "$MVNW_VERBOSE" = true ]; then 233 | echo "Found wget ... using wget" 234 | fi 235 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 236 | wget "$jarUrl" -O "$wrapperJarPath" 237 | else 238 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" 239 | fi 240 | elif command -v curl > /dev/null; then 241 | if [ "$MVNW_VERBOSE" = true ]; then 242 | echo "Found curl ... using curl" 243 | fi 244 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 245 | curl -o "$wrapperJarPath" "$jarUrl" -f 246 | else 247 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 248 | fi 249 | 250 | else 251 | if [ "$MVNW_VERBOSE" = true ]; then 252 | echo "Falling back to using Java to download" 253 | fi 254 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 255 | # For Cygwin, switch paths to Windows format before running javac 256 | if $cygwin; then 257 | javaClass=`cygpath --path --windows "$javaClass"` 258 | fi 259 | if [ -e "$javaClass" ]; then 260 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 261 | if [ "$MVNW_VERBOSE" = true ]; then 262 | echo " - Compiling MavenWrapperDownloader.java ..." 263 | fi 264 | # Compiling the Java class 265 | ("$JAVA_HOME/bin/javac" "$javaClass") 266 | fi 267 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 268 | # Running the downloader 269 | if [ "$MVNW_VERBOSE" = true ]; then 270 | echo " - Running MavenWrapperDownloader.java ..." 271 | fi 272 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 273 | fi 274 | fi 275 | fi 276 | fi 277 | ########################################################################################## 278 | # End of extension 279 | ########################################################################################## 280 | 281 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 282 | if [ "$MVNW_VERBOSE" = true ]; then 283 | echo $MAVEN_PROJECTBASEDIR 284 | fi 285 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 286 | 287 | # For Cygwin, switch paths to Windows format before running java 288 | if $cygwin; then 289 | [ -n "$M2_HOME" ] && 290 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 291 | [ -n "$JAVA_HOME" ] && 292 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 293 | [ -n "$CLASSPATH" ] && 294 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 295 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 296 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 297 | fi 298 | 299 | # Provide a "standardized" way to retrieve the CLI args that will 300 | # work with both Windows and non-Windows executions. 301 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 302 | export MAVEN_CMD_LINE_ARGS 303 | 304 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 305 | 306 | exec "$JAVACMD" \ 307 | $MAVEN_OPTS \ 308 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 309 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 310 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 311 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" 124 | 125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 162 | if ERRORLEVEL 1 goto error 163 | goto end 164 | 165 | :error 166 | set ERROR_CODE=1 167 | 168 | :end 169 | @endlocal & set ERROR_CODE=%ERROR_CODE% 170 | 171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 175 | :skipRcPost 176 | 177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 179 | 180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 181 | 182 | exit /B %ERROR_CODE% 183 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.1.RELEASE 9 | 10 | 11 | io.security 12 | corespringsecurity 13 | 0.0.1-SNAPSHOT 14 | corespringsecurity 15 | Core Spring Security 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-data-jpa 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-security 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-thymeleaf 33 | 34 | 35 | org.thymeleaf.extras 36 | thymeleaf-extras-springsecurity5 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-web 41 | 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-devtools 46 | runtime 47 | true 48 | 49 | 50 | org.postgresql 51 | postgresql 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-configuration-processor 56 | true 57 | 58 | 59 | org.projectlombok 60 | lombok 61 | true 62 | 63 | 64 | org.modelmapper 65 | modelmapper 66 | 2.3.0 67 | 68 | 69 | org.springframework.boot 70 | spring-boot-starter-test 71 | test 72 | 73 | 74 | org.junit.vintage 75 | junit-vintage-engine 76 | 77 | 78 | 79 | 80 | org.springframework.security 81 | spring-security-test 82 | test 83 | 84 | 85 | 86 | 87 | 88 | 89 | org.springframework.boot 90 | spring-boot-maven-plugin 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /src/main/ajax.http: -------------------------------------------------------------------------------- 1 | ### Send POST request with body as parameters 2 | POST http://localhost:8080/api/login 3 | Content-Type: application/json 4 | X-Requested-With: XMLHttpRequest 5 | 6 | { 7 | "username": "user", 8 | "password": "1111" 9 | } 10 | 11 | ### Send POST request with body as parameters 12 | POST http://localhost:8080/mypage 13 | Content-Type: application/json 14 | X-Requested-With: XMLHttpRequest 15 | 16 | ### -------------------------------------------------------------------------------- /src/main/csrf.http: -------------------------------------------------------------------------------- 1 | ### Send POST request with body as parameters 2 | POST http://localhost:8080/login_proc 3 | Content-Type: application/x-www-form-urlencoded 4 | 5 | username=admin&password=1111&secret_key=secret 6 | 7 | ### Send POST request with body as parameters 8 | POST http://localhost:8080/mypage 9 | Content-Type: application/x-www-form-urlencoded 10 | 11 | username=admin&password=1111&secret_key=secret 12 | 13 | ### -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/CoreSpringSecurityApplication.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cache.annotation.EnableCaching; 6 | import org.springframework.context.annotation.EnableAspectJAutoProxy; 7 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 8 | import org.springframework.scheduling.annotation.EnableAsync; 9 | 10 | @SpringBootApplication 11 | public class CoreSpringSecurityApplication { 12 | 13 | public static void main(String[] args) { 14 | 15 | SpringApplication.run(CoreSpringSecurityApplication.class, args); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/aopsecurity/AopLiveMethodService.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.aopsecurity; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | @Service 6 | public class AopLiveMethodService { 7 | 8 | public void liveMethodSecured(){ 9 | 10 | System.out.println("liveMethodSecured"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/aopsecurity/AopMethodService.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.aopsecurity; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | @Service 6 | public class AopMethodService { 7 | 8 | public void methodSecured() { 9 | System.out.println("methodSecured"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/aopsecurity/AopPointcutService.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.aopsecurity; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | @Service 6 | public class AopPointcutService { 7 | 8 | public void pointcutSecured(){ 9 | System.out.println("pointcutSecured"); 10 | } 11 | 12 | public void notSecured(){ 13 | System.out.println("notSecured"); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/aopsecurity/AopSecurityController.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.aopsecurity; 2 | 3 | import io.security.corespringsecurity.domain.dto.AccountDto; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.security.access.prepost.PreAuthorize; 6 | import org.springframework.stereotype.Controller; 7 | import org.springframework.ui.Model; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | 10 | import java.security.Principal; 11 | 12 | @Controller 13 | public class AopSecurityController { 14 | 15 | @Autowired 16 | private AopMethodService aopMethodService; 17 | 18 | @Autowired 19 | private AopPointcutService aopPointcutService; 20 | 21 | @Autowired 22 | private AopLiveMethodService aopLiveMethodService ; 23 | 24 | @GetMapping("/preAuthorize") 25 | @PreAuthorize("hasRole('ROLE_USER') and #account.username == principal.username") 26 | public String preAuthorize(AccountDto account, Model model, Principal principal){ 27 | 28 | model.addAttribute("method", "Success @PreAuthorize"); 29 | 30 | return "aop/method"; 31 | 32 | } 33 | 34 | @GetMapping("/methodSecured") 35 | public String methodSecured(Model model){ 36 | 37 | aopMethodService.methodSecured(); 38 | model.addAttribute("method", "Success MethodSecured"); 39 | 40 | return "aop/method"; 41 | } 42 | 43 | @GetMapping("/pointcutSecured") 44 | public String pointcutSecured(Model model){ 45 | 46 | aopPointcutService.notSecured(); 47 | aopPointcutService.pointcutSecured(); 48 | model.addAttribute("method", "Success PointcutSecured"); 49 | 50 | return "aop/method"; 51 | } 52 | 53 | @GetMapping("/liveMethodSecured") 54 | public String liveMethodSecured(Model model){ 55 | 56 | aopLiveMethodService.liveMethodSecured(); 57 | model.addAttribute("method", "Success LiveMethodSecured"); 58 | 59 | return "aop/method"; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/controller/HomeController.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.controller; 2 | 3 | 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | 7 | @Controller 8 | public class HomeController { 9 | 10 | @GetMapping(value="/") 11 | public String home() throws Exception { 12 | return "home"; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/controller/admin/AdminController.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.controller.admin; 2 | 3 | 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | 7 | @Controller 8 | public class AdminController { 9 | 10 | @GetMapping(value="/admin") 11 | public String home() throws Exception { 12 | return "admin/home"; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/controller/admin/ConfigController.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.controller.admin; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | 6 | @Controller 7 | public class ConfigController { 8 | 9 | @GetMapping("/config") 10 | public String config(){ 11 | return "admin/config"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/controller/admin/ResourcesController.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.controller.admin; 2 | 3 | 4 | import io.security.corespringsecurity.domain.dto.ResourcesDto; 5 | import io.security.corespringsecurity.domain.entity.Resources; 6 | import io.security.corespringsecurity.domain.entity.Role; 7 | import io.security.corespringsecurity.repository.RoleRepository; 8 | import io.security.corespringsecurity.security.metadatasource.UrlFilterInvocationSecurityMetadataSource; 9 | import io.security.corespringsecurity.service.MethodSecurityService; 10 | import io.security.corespringsecurity.service.ResourcesService; 11 | import io.security.corespringsecurity.service.RoleService; 12 | import org.modelmapper.ModelMapper; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.stereotype.Controller; 15 | import org.springframework.ui.Model; 16 | import org.springframework.web.bind.annotation.GetMapping; 17 | import org.springframework.web.bind.annotation.PathVariable; 18 | import org.springframework.web.bind.annotation.PostMapping; 19 | 20 | import java.util.HashSet; 21 | import java.util.List; 22 | import java.util.Set; 23 | 24 | @Controller 25 | public class ResourcesController { 26 | 27 | @Autowired 28 | private ResourcesService resourcesService; 29 | 30 | @Autowired 31 | private RoleRepository roleRepository; 32 | 33 | @Autowired 34 | private RoleService roleService; 35 | 36 | @Autowired 37 | private MethodSecurityService methodSecurityService; 38 | 39 | @Autowired 40 | private UrlFilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource; 41 | 42 | @GetMapping(value="/admin/resources") 43 | public String getResources(Model model) throws Exception { 44 | 45 | List resources = resourcesService.getResources(); 46 | model.addAttribute("resources", resources); 47 | 48 | return "admin/resource/list"; 49 | } 50 | 51 | @PostMapping(value="/admin/resources") 52 | public String createResources(ResourcesDto resourcesDto) throws Exception { 53 | 54 | ModelMapper modelMapper = new ModelMapper(); 55 | Role role = roleRepository.findByRoleName(resourcesDto.getRoleName()); 56 | Set roles = new HashSet<>(); 57 | roles.add(role); 58 | Resources resources = modelMapper.map(resourcesDto, Resources.class); 59 | resources.setRoleSet(roles); 60 | 61 | resourcesService.createResources(resources); 62 | 63 | if("url".equals(resourcesDto.getResourceType())){ 64 | filterInvocationSecurityMetadataSource.reload(); 65 | }else{ 66 | methodSecurityService.addMethodSecured(resourcesDto.getResourceName(),resourcesDto.getRoleName()); 67 | } 68 | 69 | return "redirect:/admin/resources"; 70 | } 71 | 72 | @GetMapping(value="/admin/resources/register") 73 | public String viewRoles(Model model) throws Exception { 74 | 75 | List roleList = roleService.getRoles(); 76 | model.addAttribute("roleList", roleList); 77 | 78 | ResourcesDto resources = new ResourcesDto(); 79 | Set roleSet = new HashSet<>(); 80 | roleSet.add(new Role()); 81 | resources.setRoleSet(roleSet); 82 | model.addAttribute("resources", resources); 83 | 84 | return "admin/resource/detail"; 85 | } 86 | 87 | @GetMapping(value="/admin/resources/{id}") 88 | public String getResources(@PathVariable String id, Model model) throws Exception { 89 | 90 | List roleList = roleService.getRoles(); 91 | model.addAttribute("roleList", roleList); 92 | Resources resources = resourcesService.getResources(Long.valueOf(id)); 93 | 94 | ModelMapper modelMapper = new ModelMapper(); 95 | ResourcesDto resourcesDto = modelMapper.map(resources, ResourcesDto.class); 96 | model.addAttribute("resources", resourcesDto); 97 | 98 | return "admin/resource/detail"; 99 | } 100 | 101 | @GetMapping(value="/admin/resources/delete/{id}") 102 | public String removeResources(@PathVariable String id, Model model) throws Exception { 103 | 104 | Resources resources = resourcesService.getResources(Long.valueOf(id)); 105 | resourcesService.deleteResources(Long.valueOf(id)); 106 | 107 | if("url".equals(resources.getResourceType())) { 108 | filterInvocationSecurityMetadataSource.reload(); 109 | }else{ 110 | methodSecurityService.removeMethodSecured(resources.getResourceName()); 111 | } 112 | 113 | return "redirect:/admin/resources"; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/controller/admin/RoleController.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.controller.admin; 2 | 3 | import io.security.corespringsecurity.domain.dto.RoleDto; 4 | import io.security.corespringsecurity.domain.entity.Resources; 5 | import io.security.corespringsecurity.domain.entity.Role; 6 | import io.security.corespringsecurity.service.RoleService; 7 | import org.modelmapper.ModelMapper; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Controller; 10 | import org.springframework.ui.Model; 11 | import org.springframework.web.bind.annotation.GetMapping; 12 | import org.springframework.web.bind.annotation.PathVariable; 13 | import org.springframework.web.bind.annotation.PostMapping; 14 | 15 | import java.util.List; 16 | 17 | @Controller 18 | public class RoleController { 19 | 20 | @Autowired 21 | private RoleService roleService; 22 | 23 | @GetMapping(value="/admin/roles") 24 | public String getRoles(Model model) throws Exception { 25 | 26 | List roles = roleService.getRoles(); 27 | model.addAttribute("roles", roles); 28 | 29 | return "admin/role/list"; 30 | } 31 | 32 | @GetMapping(value="/admin/roles/register") 33 | public String viewRoles(Model model) throws Exception { 34 | 35 | RoleDto role = new RoleDto(); 36 | model.addAttribute("role", role); 37 | 38 | return "admin/role/detail"; 39 | } 40 | 41 | @PostMapping(value="/admin/roles") 42 | public String createRole(RoleDto roleDto) throws Exception { 43 | 44 | ModelMapper modelMapper = new ModelMapper(); 45 | Role role = modelMapper.map(roleDto, Role.class); 46 | roleService.createRole(role); 47 | 48 | return "redirect:/admin/roles"; 49 | } 50 | 51 | @GetMapping(value="/admin/roles/{id}") 52 | public String getRole(@PathVariable String id, Model model) throws Exception { 53 | 54 | Role role = roleService.getRole(Long.valueOf(id)); 55 | 56 | ModelMapper modelMapper = new ModelMapper(); 57 | RoleDto roleDto = modelMapper.map(role, RoleDto.class); 58 | model.addAttribute("role", roleDto); 59 | 60 | return "admin/role/detail"; 61 | } 62 | 63 | @GetMapping(value="/admin/roles/delete/{id}") 64 | public String removeResources(@PathVariable String id, Model model) throws Exception { 65 | 66 | Role role = roleService.getRole(Long.valueOf(id)); 67 | roleService.deleteRole(Long.valueOf(id)); 68 | 69 | return "redirect:/admin/resources"; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/controller/admin/UserManagerController.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.controller.admin; 2 | 3 | 4 | import io.security.corespringsecurity.domain.dto.AccountDto; 5 | import io.security.corespringsecurity.domain.entity.Account; 6 | import io.security.corespringsecurity.domain.entity.Role; 7 | import io.security.corespringsecurity.service.RoleService; 8 | import io.security.corespringsecurity.service.UserService; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Controller; 11 | import org.springframework.ui.Model; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.PathVariable; 14 | import org.springframework.web.bind.annotation.PostMapping; 15 | 16 | import java.util.List; 17 | 18 | @Controller 19 | public class UserManagerController { 20 | 21 | @Autowired 22 | private UserService userService; 23 | 24 | @Autowired 25 | private RoleService roleService; 26 | 27 | @GetMapping(value="/admin/accounts") 28 | public String getUsers(Model model) throws Exception { 29 | 30 | List accounts = userService.getUsers(); 31 | model.addAttribute("accounts", accounts); 32 | 33 | return "admin/user/list"; 34 | } 35 | 36 | @PostMapping(value="/admin/accounts") 37 | public String modifyUser(AccountDto accountDto) throws Exception { 38 | 39 | userService.modifyUser(accountDto); 40 | 41 | return "redirect:/admin/accounts"; 42 | } 43 | 44 | @GetMapping(value = "/admin/accounts/{id}") 45 | public String getUser(@PathVariable(value = "id") Long id, Model model) { 46 | 47 | AccountDto accountDto = userService.getUser(id); 48 | List roleList = roleService.getRoles(); 49 | 50 | model.addAttribute("account", accountDto); 51 | model.addAttribute("roleList", roleList); 52 | 53 | return "admin/user/detail"; 54 | } 55 | 56 | @GetMapping(value = "/admin/accounts/delete/{id}") 57 | public String removeUser(@PathVariable(value = "id") Long id, Model model) { 58 | 59 | userService.deleteUser(id); 60 | 61 | return "redirect:/admin/users"; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/controller/login/LoginController.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.controller.login; 2 | 3 | 4 | import io.security.corespringsecurity.domain.entity.Account; 5 | import io.security.corespringsecurity.security.token.AjaxAuthenticationToken; 6 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 7 | import org.springframework.security.core.Authentication; 8 | import org.springframework.security.core.context.SecurityContextHolder; 9 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 10 | import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; 11 | import org.springframework.stereotype.Controller; 12 | import org.springframework.ui.Model; 13 | import org.springframework.web.bind.annotation.GetMapping; 14 | import org.springframework.web.bind.annotation.RequestMapping; 15 | import org.springframework.web.bind.annotation.RequestParam; 16 | 17 | import javax.servlet.http.HttpServletRequest; 18 | import javax.servlet.http.HttpServletResponse; 19 | import java.security.Principal; 20 | 21 | @Controller 22 | public class LoginController { 23 | 24 | @RequestMapping(value="/login") 25 | public String login(@RequestParam(value = "error", required = false) String error, 26 | @RequestParam(value = "exception", required = false) String exception, Model model){ 27 | model.addAttribute("error",error); 28 | model.addAttribute("exception",exception); 29 | return "login"; 30 | } 31 | 32 | @GetMapping(value = "/logout") 33 | public String logout(HttpServletRequest request, HttpServletResponse response) throws Exception { 34 | 35 | Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 36 | if (authentication != null){ 37 | new SecurityContextLogoutHandler().logout(request, response, authentication); 38 | } 39 | 40 | return "redirect:/login"; 41 | } 42 | 43 | @GetMapping(value="/denied") 44 | public String accessDenied(@RequestParam(value = "exception", required = false) String exception, Principal principal, Model model) throws Exception { 45 | 46 | Account account = null; 47 | 48 | if (principal instanceof UsernamePasswordAuthenticationToken) { 49 | account = (Account) ((UsernamePasswordAuthenticationToken) principal).getPrincipal(); 50 | 51 | }else if(principal instanceof AjaxAuthenticationToken){ 52 | account = (Account) ((AjaxAuthenticationToken) principal).getPrincipal(); 53 | } 54 | 55 | model.addAttribute("username", account.getUsername()); 56 | model.addAttribute("exception", exception); 57 | 58 | return "user/login/denied"; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/controller/user/MessageController.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.controller.user; 2 | 3 | 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | 7 | @Controller 8 | public class MessageController { 9 | 10 | @GetMapping(value="/messages") 11 | public String messages() throws Exception { 12 | 13 | return "user/messages"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/controller/user/UserController.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.controller.user; 2 | 3 | 4 | import io.security.corespringsecurity.domain.dto.AccountDto; 5 | import io.security.corespringsecurity.domain.entity.Account; 6 | import io.security.corespringsecurity.domain.entity.Role; 7 | import io.security.corespringsecurity.repository.RoleRepository; 8 | import io.security.corespringsecurity.security.service.AccountContext; 9 | import io.security.corespringsecurity.security.token.AjaxAuthenticationToken; 10 | import io.security.corespringsecurity.service.UserService; 11 | import org.modelmapper.ModelMapper; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.security.access.annotation.Secured; 14 | import org.springframework.security.access.prepost.PreAuthorize; 15 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 16 | import org.springframework.security.core.Authentication; 17 | import org.springframework.security.core.annotation.AuthenticationPrincipal; 18 | import org.springframework.security.core.context.SecurityContextHolder; 19 | import org.springframework.security.crypto.password.PasswordEncoder; 20 | import org.springframework.stereotype.Controller; 21 | import org.springframework.web.bind.annotation.GetMapping; 22 | import org.springframework.web.bind.annotation.PostMapping; 23 | 24 | import java.security.Principal; 25 | import java.util.Arrays; 26 | import java.util.HashSet; 27 | import java.util.Set; 28 | 29 | @Controller 30 | public class UserController { 31 | 32 | @Autowired 33 | private UserService userService; 34 | 35 | @Autowired 36 | private PasswordEncoder passwordEncoder; 37 | 38 | @Autowired 39 | private RoleRepository roleRepository; 40 | 41 | @GetMapping(value="/users") 42 | public String createUser() throws Exception { 43 | 44 | return "user/login/register"; 45 | } 46 | 47 | @PostMapping(value="/users") 48 | public String createUser(AccountDto accountDto) throws Exception { 49 | 50 | ModelMapper modelMapper = new ModelMapper(); 51 | Account account = modelMapper.map(accountDto, Account.class); 52 | account.setPassword(passwordEncoder.encode(accountDto.getPassword())); 53 | 54 | userService.createUser(account); 55 | 56 | return "redirect:/"; 57 | } 58 | 59 | @GetMapping(value="/mypage") 60 | public String myPage(@AuthenticationPrincipal Account account, Authentication authentication, Principal principal) throws Exception { 61 | return "user/mypage"; 62 | } 63 | 64 | @GetMapping("/order") 65 | public String order(){ 66 | userService.order(); 67 | return "user/mypage"; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/domain/dto/AccountDto.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.domain.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.List; 9 | 10 | @Data 11 | @Builder 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class AccountDto { 15 | 16 | private String id; 17 | private String username; 18 | private String email; 19 | private int age; 20 | private String password; 21 | private List roles; 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/domain/dto/ResourcesDto.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.domain.dto; 2 | 3 | import io.security.corespringsecurity.domain.entity.Role; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.util.List; 10 | import java.util.Set; 11 | 12 | @Data 13 | @Builder 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class ResourcesDto{ 17 | 18 | private String id; 19 | private String resourceName; 20 | private String httpMethod; 21 | private int orderNum; 22 | private String resourceType; 23 | private String roleName; 24 | private Set roleSet; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/domain/dto/RoleDto.java: -------------------------------------------------------------------------------- 1 | 2 | package io.security.corespringsecurity.domain.dto; 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | @Data 10 | @Builder 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | public class RoleDto{ 14 | 15 | private String id; 16 | private String roleName; 17 | private String roleDesc; 18 | 19 | } 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/domain/entity/AccessIp.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.domain.entity; 2 | 3 | import lombok.*; 4 | 5 | import javax.persistence.*; 6 | import java.io.Serializable; 7 | 8 | @Entity 9 | @Table(name = "ACCESS_IP") 10 | @Data 11 | @EqualsAndHashCode(of = "id") 12 | @Builder 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | public class AccessIp implements Serializable { 16 | 17 | @Id 18 | @GeneratedValue 19 | @Column(name = "IP_ID", unique = true, nullable = false) 20 | private Long id; 21 | 22 | @Column(name = "IP_ADDRESS", nullable = false) 23 | private String ipAddress; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/domain/entity/Account.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.domain.entity; 2 | 3 | import lombok.*; 4 | 5 | import javax.persistence.*; 6 | import java.io.Serializable; 7 | import java.util.HashSet; 8 | import java.util.Set; 9 | 10 | @Entity 11 | @Data 12 | @ToString(exclude = {"userRoles"}) 13 | @Builder 14 | @EqualsAndHashCode(of = "id") 15 | @NoArgsConstructor 16 | @AllArgsConstructor 17 | public class Account implements Serializable { 18 | 19 | @Id 20 | @GeneratedValue 21 | private Long id; 22 | 23 | @Column 24 | private String username; 25 | 26 | @Column 27 | private String email; 28 | 29 | @Column 30 | private int age; 31 | 32 | @Column 33 | private String password; 34 | 35 | @ManyToMany(fetch = FetchType.LAZY, cascade={CascadeType.ALL}) 36 | @JoinTable(name = "account_roles", joinColumns = { @JoinColumn(name = "account_id") }, inverseJoinColumns = { 37 | @JoinColumn(name = "role_id") }) 38 | private Set userRoles = new HashSet<>(); 39 | } 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/domain/entity/Resources.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.domain.entity; 2 | 3 | import lombok.*; 4 | import org.springframework.data.jpa.domain.support.AuditingEntityListener; 5 | 6 | import javax.persistence.*; 7 | import java.io.Serializable; 8 | import java.util.HashSet; 9 | import java.util.Set; 10 | 11 | @Entity 12 | @Table(name = "RESOURCES") 13 | @Data 14 | @ToString(exclude = {"roleSet"}) 15 | @EntityListeners(value = { AuditingEntityListener.class }) 16 | @EqualsAndHashCode(of = "id") 17 | @Builder 18 | @NoArgsConstructor 19 | @AllArgsConstructor 20 | public class Resources implements Serializable { 21 | 22 | @Id 23 | @GeneratedValue 24 | @Column(name = "resource_id") 25 | private Long id; 26 | 27 | @Column(name = "resource_name") 28 | private String resourceName; 29 | 30 | @Column(name = "http_method") 31 | private String httpMethod; 32 | 33 | @Column(name = "order_num") 34 | private int orderNum; 35 | 36 | @Column(name = "resource_type") 37 | private String resourceType; 38 | 39 | @ManyToMany(fetch = FetchType.LAZY) 40 | @JoinTable(name = "role_resources", joinColumns = { 41 | @JoinColumn(name = "resource_id") }, inverseJoinColumns = { @JoinColumn(name = "role_id") }) 42 | private Set roleSet = new HashSet<>(); 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/domain/entity/Role.java: -------------------------------------------------------------------------------- 1 | 2 | package io.security.corespringsecurity.domain.entity; 3 | 4 | import lombok.*; 5 | 6 | import javax.persistence.*; 7 | import java.io.Serializable; 8 | import java.util.HashSet; 9 | import java.util.LinkedHashSet; 10 | import java.util.Set; 11 | 12 | @Entity 13 | @Table(name = "ROLE") 14 | @Getter 15 | @Setter 16 | @ToString(exclude = {"users","resourcesSet"}) 17 | @Builder 18 | @NoArgsConstructor 19 | @AllArgsConstructor 20 | @EqualsAndHashCode(of = "id") 21 | public class Role implements Serializable { 22 | 23 | @Id 24 | @GeneratedValue 25 | @Column(name = "role_id") 26 | private Long id; 27 | 28 | @Column(name = "role_name") 29 | private String roleName; 30 | 31 | @Column(name = "role_desc") 32 | private String roleDesc; 33 | 34 | @ManyToMany(fetch = FetchType.LAZY, mappedBy = "roleSet") 35 | @OrderBy("ordernum desc") 36 | private Set resourcesSet = new LinkedHashSet<>(); 37 | 38 | @ManyToMany(fetch = FetchType.LAZY, mappedBy = "userRoles") 39 | private Set accounts = new HashSet<>(); 40 | 41 | } 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/domain/entity/RoleHierarchy.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.domain.entity; 2 | 3 | import lombok.*; 4 | 5 | import javax.persistence.*; 6 | import java.io.Serializable; 7 | import java.util.HashSet; 8 | import java.util.Set; 9 | 10 | @Entity 11 | @Table(name="ROLE_HIERARCHY") 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | @Getter 15 | @Setter 16 | @Builder 17 | public class RoleHierarchy implements Serializable { 18 | 19 | @Id 20 | @GeneratedValue 21 | private Long id; 22 | 23 | @Column(name = "child_name") 24 | private String childName; 25 | 26 | @ManyToOne(cascade = {CascadeType.ALL},fetch = FetchType.LAZY) 27 | @JoinColumn(name = "parent_name", referencedColumnName = "child_name") 28 | private RoleHierarchy parentName; 29 | 30 | @OneToMany(mappedBy = "parentName", cascade={CascadeType.ALL}) 31 | private Set roleHierarchy = new HashSet(); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/repository/AccessIpRepository.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.repository; 2 | 3 | import io.security.corespringsecurity.domain.entity.AccessIp; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface AccessIpRepository extends JpaRepository { 7 | 8 | AccessIp findByIpAddress(String IpAddress); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/repository/ResourcesRepository.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.repository; 2 | 3 | import io.security.corespringsecurity.domain.entity.Resources; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.Query; 6 | 7 | import java.util.List; 8 | 9 | public interface ResourcesRepository extends JpaRepository { 10 | 11 | Resources findByResourceNameAndHttpMethod(String resourceName, String httpMethod); 12 | 13 | @Query("select r from Resources r join fetch r.roleSet where r.resourceType = 'url' order by r.orderNum desc") 14 | List findAllResources(); 15 | 16 | @Query("select r from Resources r join fetch r.roleSet where r.resourceType = 'method' order by r.orderNum desc") 17 | List findAllMethodResources(); 18 | 19 | @Query("select r from Resources r join fetch r.roleSet where r.resourceType = 'pointcut' order by r.orderNum desc") 20 | List findAllPointcutResources(); 21 | } -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/repository/RoleHierarchyRepository.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.repository; 2 | 3 | import io.security.corespringsecurity.domain.entity.RoleHierarchy; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface RoleHierarchyRepository extends JpaRepository { 7 | 8 | RoleHierarchy findByChildName(String roleName); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/repository/RoleRepository.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.repository; 2 | 3 | 4 | import io.security.corespringsecurity.domain.entity.Role; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | public interface RoleRepository extends JpaRepository { 8 | 9 | Role findByRoleName(String name); 10 | 11 | @Override 12 | void delete(Role role); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.repository; 2 | 3 | import io.security.corespringsecurity.domain.entity.Account; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface UserRepository extends JpaRepository { 7 | Account findByUsername(String username); 8 | int countByUsername(String username); 9 | } -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/common/AjaxLoginAuthenticationEntryPoint.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.common; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import org.springframework.http.HttpStatus; 5 | import org.springframework.http.MediaType; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.security.core.AuthenticationException; 8 | import org.springframework.security.web.AuthenticationEntryPoint; 9 | import org.springframework.web.bind.annotation.ResponseBody; 10 | 11 | import javax.servlet.ServletException; 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletResponse; 14 | import java.io.IOException; 15 | 16 | public class AjaxLoginAuthenticationEntryPoint implements AuthenticationEntryPoint { 17 | 18 | private ObjectMapper objectMapper = new ObjectMapper(); 19 | 20 | @Override 21 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { 22 | 23 | response.setContentType(MediaType.APPLICATION_JSON_VALUE); 24 | response.setStatus(HttpStatus.UNAUTHORIZED.value()); 25 | response.getWriter().write(objectMapper.writeValueAsString(HttpServletResponse.SC_UNAUTHORIZED)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/common/FormWebAuthenticationDetails.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.common; 2 | 3 | import org.springframework.security.web.authentication.WebAuthenticationDetails; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | 7 | public class FormWebAuthenticationDetails extends WebAuthenticationDetails { 8 | 9 | private String secretKey; 10 | 11 | public FormWebAuthenticationDetails(HttpServletRequest request) { 12 | super(request); 13 | secretKey = request.getParameter("secret_key"); 14 | } 15 | 16 | public String getSecretKey() { 17 | 18 | return secretKey; 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/common/FormWebAuthenticationDetailsSource.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.common; 2 | 3 | import org.springframework.security.authentication.AuthenticationDetailsSource; 4 | import org.springframework.security.web.authentication.WebAuthenticationDetails; 5 | import org.springframework.stereotype.Component; 6 | 7 | import javax.servlet.http.HttpServletRequest; 8 | 9 | @Component 10 | public class FormWebAuthenticationDetailsSource implements AuthenticationDetailsSource { 11 | @Override 12 | public WebAuthenticationDetails buildDetails(HttpServletRequest request) { 13 | return new FormWebAuthenticationDetails(request); 14 | } 15 | } -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/configs/AjaxLoginConfigurer.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.configs; 2 | 3 | import io.security.corespringsecurity.security.filter.AjaxLoginProcessingFilter; 4 | import org.springframework.security.authentication.AuthenticationManager; 5 | import org.springframework.security.config.annotation.web.HttpSecurityBuilder; 6 | import org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer; 7 | import org.springframework.security.web.authentication.AuthenticationFailureHandler; 8 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler; 9 | import org.springframework.security.web.authentication.RememberMeServices; 10 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 11 | import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; 12 | import org.springframework.security.web.util.matcher.AntPathRequestMatcher; 13 | import org.springframework.security.web.util.matcher.RequestMatcher; 14 | 15 | public final class AjaxLoginConfigurer> extends 16 | AbstractAuthenticationFilterConfigurer, AjaxLoginProcessingFilter> { 17 | 18 | private AuthenticationSuccessHandler successHandler; 19 | private AuthenticationFailureHandler failureHandler; 20 | private AuthenticationManager authenticationManager; 21 | 22 | public AjaxLoginConfigurer() { 23 | super(new AjaxLoginProcessingFilter(), null); 24 | } 25 | 26 | @Override 27 | public void init(H http) throws Exception { 28 | super.init(http); 29 | } 30 | 31 | @Override 32 | public void configure(H http) { 33 | 34 | if(authenticationManager == null){ 35 | authenticationManager = http.getSharedObject(AuthenticationManager.class); 36 | } 37 | getAuthenticationFilter().setAuthenticationManager(authenticationManager); 38 | getAuthenticationFilter().setAuthenticationSuccessHandler(successHandler); 39 | getAuthenticationFilter().setAuthenticationFailureHandler(failureHandler); 40 | 41 | SessionAuthenticationStrategy sessionAuthenticationStrategy = http 42 | .getSharedObject(SessionAuthenticationStrategy.class); 43 | if (sessionAuthenticationStrategy != null) { 44 | getAuthenticationFilter().setSessionAuthenticationStrategy(sessionAuthenticationStrategy); 45 | } 46 | RememberMeServices rememberMeServices = http 47 | .getSharedObject(RememberMeServices.class); 48 | if (rememberMeServices != null) { 49 | getAuthenticationFilter().setRememberMeServices(rememberMeServices); 50 | } 51 | http.setSharedObject(AjaxLoginProcessingFilter.class,getAuthenticationFilter()); 52 | http.addFilterBefore(getAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); 53 | } 54 | 55 | public AjaxLoginConfigurer loginPage(String loginPage) { 56 | return super.loginPage(loginPage); 57 | } 58 | 59 | public AjaxLoginConfigurer successHandlerAjax(AuthenticationSuccessHandler successHandler) { 60 | this.successHandler = successHandler; 61 | return this; 62 | } 63 | 64 | public AjaxLoginConfigurer failureHandlerAjax(AuthenticationFailureHandler authenticationFailureHandler) { 65 | this.failureHandler = authenticationFailureHandler; 66 | return this; 67 | } 68 | 69 | public AjaxLoginConfigurer setAuthenticationManager(AuthenticationManager authenticationManager) { 70 | this.authenticationManager = authenticationManager; 71 | return this; 72 | } 73 | 74 | @Override 75 | protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) { 76 | return new AntPathRequestMatcher(loginProcessingUrl, "POST"); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/configs/AjaxSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.configs; 2 | 3 | import io.security.corespringsecurity.security.common.AjaxLoginAuthenticationEntryPoint; 4 | import io.security.corespringsecurity.security.handler.AjaxAccessDeniedHandler; 5 | import io.security.corespringsecurity.security.handler.AjaxAuthenticationFailureHandler; 6 | import io.security.corespringsecurity.security.handler.AjaxAuthenticationSuccessHandler; 7 | import io.security.corespringsecurity.security.provider.AjaxAuthenticationProvider; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.core.annotation.Order; 11 | import org.springframework.security.authentication.AuthenticationProvider; 12 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 13 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 14 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 15 | import org.springframework.security.web.access.AccessDeniedHandler; 16 | import org.springframework.security.web.authentication.AuthenticationFailureHandler; 17 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler; 18 | 19 | @Configuration 20 | @Order(0) 21 | public class AjaxSecurityConfig extends WebSecurityConfigurerAdapter { 22 | 23 | @Override 24 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 25 | auth.authenticationProvider(ajaxAuthenticationProvider()); 26 | } 27 | 28 | @Bean 29 | public AuthenticationProvider ajaxAuthenticationProvider() { 30 | return new AjaxAuthenticationProvider(); 31 | } 32 | 33 | @Bean 34 | public AuthenticationSuccessHandler ajaxAuthenticationSuccessHandler(){ 35 | return new AjaxAuthenticationSuccessHandler(); 36 | } 37 | 38 | @Bean 39 | public AuthenticationFailureHandler ajaxAuthenticationFailureHandler(){ 40 | return new AjaxAuthenticationFailureHandler(); 41 | } 42 | 43 | @Bean 44 | public AccessDeniedHandler ajaxAccessDeniedHandler(){ 45 | return new AjaxAccessDeniedHandler(); 46 | } 47 | 48 | @Override 49 | protected void configure(HttpSecurity http) throws Exception { 50 | http 51 | .antMatcher("/api/**") 52 | .authorizeRequests() 53 | .antMatchers("/api/messages").hasRole("MANAGER") 54 | .antMatchers("/api/login").permitAll() 55 | .anyRequest().authenticated() 56 | .and() 57 | .exceptionHandling() 58 | .authenticationEntryPoint(new AjaxLoginAuthenticationEntryPoint()) 59 | .accessDeniedHandler(ajaxAccessDeniedHandler()); 60 | 61 | // http.csrf().disable(); 62 | ajaxConfigurer(http); 63 | } 64 | 65 | private void ajaxConfigurer(HttpSecurity http) throws Exception { 66 | http 67 | .apply(new AjaxLoginConfigurer<>()) 68 | .successHandlerAjax(ajaxAuthenticationSuccessHandler()) 69 | .failureHandlerAjax(ajaxAuthenticationFailureHandler()) 70 | .loginPage("/api/login") 71 | .loginProcessingUrl("/api/login") 72 | .setAuthenticationManager(authenticationManagerBean()); 73 | } 74 | 75 | } 76 | 77 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/configs/MethodSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.configs; 2 | 3 | import io.security.corespringsecurity.security.factory.MethodResourcesMapFactoryBean; 4 | import io.security.corespringsecurity.security.interceptor.CustomMethodSecurityInterceptor; 5 | import io.security.corespringsecurity.security.processor.ProtectPointcutPostProcessor; 6 | import io.security.corespringsecurity.service.SecurityResourceService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.context.annotation.Profile; 11 | import org.springframework.security.access.intercept.RunAsManager; 12 | import org.springframework.security.access.method.MapBasedMethodSecurityMetadataSource; 13 | import org.springframework.security.access.method.MethodSecurityMetadataSource; 14 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 15 | import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration; 16 | 17 | @Configuration 18 | @EnableGlobalMethodSecurity 19 | public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration { 20 | 21 | @Autowired 22 | private SecurityResourceService securityResourceService; 23 | 24 | @Override 25 | protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() { 26 | return mapBasedMethodSecurityMetadataSource(); 27 | } 28 | 29 | @Bean 30 | public MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource() { 31 | return new MapBasedMethodSecurityMetadataSource(methodResourcesMapFactoryBean().getObject()); 32 | } 33 | 34 | @Bean 35 | public MethodResourcesMapFactoryBean methodResourcesMapFactoryBean(){ 36 | MethodResourcesMapFactoryBean methodResourcesMapFactoryBean = new MethodResourcesMapFactoryBean(); 37 | methodResourcesMapFactoryBean.setSecurityResourceService(securityResourceService); 38 | methodResourcesMapFactoryBean.setResourceType("method"); 39 | return methodResourcesMapFactoryBean; 40 | } 41 | 42 | @Bean 43 | @Profile("pointcut") 44 | public MethodResourcesMapFactoryBean pointcutResourcesMapFactoryBean(){ 45 | MethodResourcesMapFactoryBean methodResourcesMapFactoryBean = new MethodResourcesMapFactoryBean(); 46 | methodResourcesMapFactoryBean.setSecurityResourceService(securityResourceService); 47 | methodResourcesMapFactoryBean.setResourceType("pointcut"); 48 | return methodResourcesMapFactoryBean; 49 | } 50 | 51 | @Bean 52 | @Profile("pointcut") 53 | public ProtectPointcutPostProcessor protectPointcutPostProcessor(){ 54 | ProtectPointcutPostProcessor protectPointcutPostProcessor = new ProtectPointcutPostProcessor(mapBasedMethodSecurityMetadataSource()); 55 | protectPointcutPostProcessor.setPointcutMap(pointcutResourcesMapFactoryBean().getObject()); 56 | return protectPointcutPostProcessor; 57 | } 58 | 59 | @Bean 60 | public CustomMethodSecurityInterceptor customMethodSecurityInterceptor(MapBasedMethodSecurityMetadataSource methodSecurityMetadataSource) { 61 | CustomMethodSecurityInterceptor customMethodSecurityInterceptor = new CustomMethodSecurityInterceptor(); 62 | customMethodSecurityInterceptor.setAccessDecisionManager(accessDecisionManager()); 63 | customMethodSecurityInterceptor.setAfterInvocationManager(afterInvocationManager()); 64 | customMethodSecurityInterceptor.setSecurityMetadataSource(methodSecurityMetadataSource); 65 | RunAsManager runAsManager = runAsManager(); 66 | if (runAsManager != null) { 67 | customMethodSecurityInterceptor.setRunAsManager(runAsManager); 68 | } 69 | 70 | return customMethodSecurityInterceptor; 71 | } 72 | 73 | // @Bean 74 | // @Profile("pointcut") 75 | // BeanPostProcessor protectPointcutPostProcessor() throws Exception { 76 | // 77 | // Class clazz = Class.forName("org.springframework.security.config.method.ProtectPointcutPostProcessor"); 78 | // Constructor declaredConstructor = clazz.getDeclaredConstructor(MapBasedMethodSecurityMetadataSource.class); 79 | // declaredConstructor.setAccessible(true); 80 | // Object instance = declaredConstructor.newInstance(mapBasedMethodSecurityMetadataSource()); 81 | // Method setPointcutMap = instance.getClass().getMethod("setPointcutMap", Map.class); 82 | // setPointcutMap.setAccessible(true); 83 | // setPointcutMap.invoke(instance, pointcutResourcesMapFactoryBean().getObject()); 84 | // 85 | // return (BeanPostProcessor)instance; 86 | // } 87 | 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/configs/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.configs; 2 | 3 | import io.security.corespringsecurity.security.common.FormWebAuthenticationDetailsSource; 4 | import io.security.corespringsecurity.security.factory.UrlResourcesMapFactoryBean; 5 | import io.security.corespringsecurity.security.filter.PermitAllFilter; 6 | import io.security.corespringsecurity.security.handler.FormAccessDeniedHandler; 7 | import io.security.corespringsecurity.security.metadatasource.UrlFilterInvocationSecurityMetadataSource; 8 | import io.security.corespringsecurity.security.provider.FormAuthenticationProvider; 9 | import io.security.corespringsecurity.security.voter.IpAddressVoter; 10 | import io.security.corespringsecurity.service.SecurityResourceService; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.boot.autoconfigure.security.servlet.PathRequest; 14 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 15 | import org.springframework.context.annotation.Bean; 16 | import org.springframework.context.annotation.Configuration; 17 | import org.springframework.security.access.AccessDecisionManager; 18 | import org.springframework.security.access.AccessDecisionVoter; 19 | import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl; 20 | import org.springframework.security.access.vote.AffirmativeBased; 21 | import org.springframework.security.access.vote.RoleHierarchyVoter; 22 | import org.springframework.security.authentication.AuthenticationManager; 23 | import org.springframework.security.authentication.AuthenticationProvider; 24 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 25 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 26 | import org.springframework.security.config.annotation.web.builders.WebSecurity; 27 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 28 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 29 | import org.springframework.security.crypto.factory.PasswordEncoderFactories; 30 | import org.springframework.security.crypto.password.PasswordEncoder; 31 | import org.springframework.security.web.access.AccessDeniedHandler; 32 | import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; 33 | import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; 34 | import org.springframework.security.web.authentication.AuthenticationFailureHandler; 35 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler; 36 | import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; 37 | 38 | import java.util.ArrayList; 39 | import java.util.List; 40 | 41 | @Configuration 42 | @EnableWebSecurity 43 | @Slf4j 44 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 45 | 46 | @Autowired 47 | private FormWebAuthenticationDetailsSource formWebAuthenticationDetailsSource; 48 | @Autowired 49 | private AuthenticationSuccessHandler formAuthenticationSuccessHandler; 50 | @Autowired 51 | private AuthenticationFailureHandler formAuthenticationFailureHandler; 52 | @Autowired 53 | private SecurityResourceService securityResourceService; 54 | 55 | private String[] permitAllResources = {"/", "/login", "/user/login/**"}; 56 | 57 | @Override 58 | public void configure(WebSecurity web) throws Exception { 59 | web.ignoring().requestMatchers(PathRequest.toStaticResources().atCommonLocations()); 60 | } 61 | 62 | @Override 63 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 64 | auth.authenticationProvider(authenticationProvider()); 65 | } 66 | 67 | @Override 68 | public AuthenticationManager authenticationManagerBean() throws Exception { 69 | return super.authenticationManagerBean(); 70 | } 71 | 72 | @Override 73 | protected void configure(final HttpSecurity http) throws Exception { 74 | http 75 | .authorizeRequests() 76 | .anyRequest().authenticated() 77 | .and() 78 | .formLogin() 79 | .loginPage("/login") 80 | .loginProcessingUrl("/login_proc") 81 | .authenticationDetailsSource(formWebAuthenticationDetailsSource) 82 | .successHandler(formAuthenticationSuccessHandler) 83 | .failureHandler(formAuthenticationFailureHandler) 84 | .permitAll() 85 | .and() 86 | .exceptionHandling() 87 | .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")) 88 | .accessDeniedPage("/denied") 89 | .accessDeniedHandler(accessDeniedHandler()) 90 | .and() 91 | .addFilterAt(customFilterSecurityInterceptor(), FilterSecurityInterceptor.class); 92 | 93 | http.csrf().disable(); 94 | } 95 | 96 | @Bean 97 | public PasswordEncoder passwordEncoder() { 98 | return PasswordEncoderFactories.createDelegatingPasswordEncoder(); 99 | } 100 | 101 | @Bean 102 | public AuthenticationProvider authenticationProvider(){ 103 | return new FormAuthenticationProvider(passwordEncoder()); 104 | } 105 | 106 | public AccessDeniedHandler accessDeniedHandler() { 107 | FormAccessDeniedHandler commonAccessDeniedHandler = new FormAccessDeniedHandler(); 108 | commonAccessDeniedHandler.setErrorPage("/denied"); 109 | return commonAccessDeniedHandler; 110 | } 111 | 112 | @Bean 113 | public PermitAllFilter customFilterSecurityInterceptor() throws Exception { 114 | 115 | PermitAllFilter permitAllFilter = new PermitAllFilter(permitAllResources); 116 | permitAllFilter.setSecurityMetadataSource(urlFilterInvocationSecurityMetadataSource()); 117 | permitAllFilter.setAccessDecisionManager(affirmativeBased()); 118 | permitAllFilter.setAuthenticationManager(authenticationManagerBean()); 119 | return permitAllFilter; 120 | } 121 | 122 | @Bean 123 | public FilterRegistrationBean filterRegistrationBean() throws Exception { 124 | FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); 125 | filterRegistrationBean.setFilter(customFilterSecurityInterceptor()); 126 | filterRegistrationBean.setEnabled(false); 127 | return filterRegistrationBean; 128 | } 129 | 130 | private AccessDecisionManager affirmativeBased() { 131 | AffirmativeBased affirmativeBased = new AffirmativeBased(getAccessDecisionVoters()); 132 | return affirmativeBased; 133 | } 134 | 135 | private List> getAccessDecisionVoters() { 136 | 137 | List> accessDecisionVoters = new ArrayList<>(); 138 | // accessDecisionVoters.add(new IpAddressVoter(securityResourceService)); 139 | accessDecisionVoters.add(roleVoter()); 140 | 141 | return accessDecisionVoters; 142 | } 143 | 144 | @Bean 145 | public AccessDecisionVoter roleVoter() { 146 | 147 | RoleHierarchyVoter roleHierarchyVoter = new RoleHierarchyVoter(roleHierarchy()); 148 | return roleHierarchyVoter; 149 | } 150 | 151 | @Bean 152 | public RoleHierarchyImpl roleHierarchy() { 153 | RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl(); 154 | return roleHierarchy; 155 | } 156 | 157 | @Bean 158 | public UrlFilterInvocationSecurityMetadataSource urlFilterInvocationSecurityMetadataSource() throws Exception { 159 | return new UrlFilterInvocationSecurityMetadataSource(urlResourcesMapFactoryBean().getObject(), securityResourceService); 160 | } 161 | 162 | private UrlResourcesMapFactoryBean urlResourcesMapFactoryBean() { 163 | 164 | UrlResourcesMapFactoryBean urlResourcesMapFactoryBean = new UrlResourcesMapFactoryBean(); 165 | urlResourcesMapFactoryBean.setSecurityResourceService(securityResourceService); 166 | 167 | return urlResourcesMapFactoryBean; 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/factory/MethodResourcesMapFactoryBean.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.factory; 2 | 3 | import io.security.corespringsecurity.service.SecurityResourceService; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.FactoryBean; 6 | import org.springframework.security.access.ConfigAttribute; 7 | 8 | import java.util.LinkedHashMap; 9 | import java.util.List; 10 | 11 | @Slf4j 12 | public class MethodResourcesMapFactoryBean implements FactoryBean>> { 13 | 14 | private SecurityResourceService securityResourceService; 15 | private String resourceType; 16 | 17 | public void setResourceType(String resourceType) { 18 | this.resourceType = resourceType; 19 | } 20 | 21 | public void setSecurityResourceService(SecurityResourceService securityResourceService) { 22 | this.securityResourceService = securityResourceService; 23 | } 24 | 25 | private LinkedHashMap> resourcesMap; 26 | 27 | public void init() { 28 | if ("method".equals(resourceType)) { 29 | resourcesMap = securityResourceService.getMethodResourceList(); 30 | }else if("pointcut".equals(resourceType)){ 31 | resourcesMap = securityResourceService.getPointcutResourceList(); 32 | } 33 | } 34 | 35 | public LinkedHashMap> getObject() { 36 | if (resourcesMap == null) { 37 | init(); 38 | } 39 | return resourcesMap; 40 | } 41 | 42 | @SuppressWarnings("rawtypes") 43 | public Class getObjectType() { 44 | return LinkedHashMap.class; 45 | } 46 | 47 | public boolean isSingleton() { 48 | return true; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/factory/UrlResourcesMapFactoryBean.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.factory; 2 | 3 | import io.security.corespringsecurity.service.SecurityResourceService; 4 | import org.springframework.beans.factory.FactoryBean; 5 | import org.springframework.security.access.ConfigAttribute; 6 | import org.springframework.security.web.util.matcher.RequestMatcher; 7 | 8 | import java.util.LinkedHashMap; 9 | import java.util.List; 10 | 11 | public class UrlResourcesMapFactoryBean implements FactoryBean>> { 12 | 13 | private SecurityResourceService securityResourceService; 14 | private LinkedHashMap> resourceMap; 15 | 16 | public void setSecurityResourceService(SecurityResourceService securityResourceService) { 17 | this.securityResourceService = securityResourceService; 18 | } 19 | 20 | @Override 21 | public LinkedHashMap> getObject() throws Exception { 22 | 23 | if(resourceMap == null){ 24 | init(); 25 | } 26 | 27 | return resourceMap; 28 | } 29 | 30 | private void init() { 31 | resourceMap = securityResourceService.getResourceList(); 32 | } 33 | 34 | @Override 35 | public Class getObjectType() { 36 | return LinkedHashMap.class; 37 | } 38 | 39 | @Override 40 | public boolean isSingleton() { 41 | return true; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/filter/AjaxLoginProcessingFilter.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.filter; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import io.security.corespringsecurity.domain.dto.AccountDto; 5 | import io.security.corespringsecurity.util.WebUtil; 6 | import io.security.corespringsecurity.security.token.AjaxAuthenticationToken; 7 | import org.springframework.http.HttpMethod; 8 | import org.springframework.security.authentication.AuthenticationServiceException; 9 | import org.springframework.security.core.Authentication; 10 | import org.springframework.security.core.AuthenticationException; 11 | import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; 12 | import org.springframework.security.web.util.matcher.AntPathRequestMatcher; 13 | import org.springframework.util.StringUtils; 14 | 15 | import javax.servlet.http.HttpServletRequest; 16 | import javax.servlet.http.HttpServletResponse; 17 | import java.io.IOException; 18 | 19 | public class AjaxLoginProcessingFilter extends AbstractAuthenticationProcessingFilter { 20 | 21 | private static final String XML_HTTP_REQUEST = "XMLHttpRequest"; 22 | private static final String X_REQUESTED_WITH = "X-Requested-With"; 23 | 24 | private ObjectMapper objectMapper = new ObjectMapper(); 25 | 26 | public AjaxLoginProcessingFilter() { 27 | super(new AntPathRequestMatcher("/ajaxLogin", "POST")); 28 | } 29 | 30 | @Override 31 | public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) 32 | throws AuthenticationException, IOException { 33 | 34 | if (!HttpMethod.POST.name().equals(request.getMethod()) || !WebUtil.isAjax(request)) { 35 | throw new IllegalArgumentException("Authentication method not supported"); 36 | } 37 | 38 | AccountDto accountDto = objectMapper.readValue(request.getReader(), AccountDto.class); 39 | 40 | if (StringUtils.isEmpty(accountDto.getUsername()) || StringUtils.isEmpty(accountDto.getPassword())) { 41 | throw new AuthenticationServiceException("Username or Password not provided"); 42 | } 43 | AjaxAuthenticationToken token = new AjaxAuthenticationToken(accountDto.getUsername(),accountDto.getPassword()); 44 | 45 | return this.getAuthenticationManager().authenticate(token); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/filter/PermitAllFilter.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.filter; 2 | 3 | import org.springframework.security.access.intercept.InterceptorStatusToken; 4 | import org.springframework.security.web.FilterInvocation; 5 | import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; 6 | import org.springframework.security.web.util.matcher.AntPathRequestMatcher; 7 | import org.springframework.security.web.util.matcher.RequestMatcher; 8 | 9 | import javax.servlet.ServletException; 10 | import javax.servlet.http.HttpServletRequest; 11 | import java.io.IOException; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | public class PermitAllFilter extends FilterSecurityInterceptor { 16 | 17 | private static final String FILTER_APPLIED = "__spring_security_filterSecurityInterceptor_filterApplied"; 18 | private boolean observeOncePerRequest = true; 19 | 20 | private List permitAllRequestMatchers = new ArrayList<>(); 21 | 22 | public PermitAllFilter(String...permitAllResources){ 23 | 24 | for(String resource : permitAllResources){ 25 | permitAllRequestMatchers.add(new AntPathRequestMatcher(resource)); 26 | } 27 | } 28 | 29 | @Override 30 | protected InterceptorStatusToken beforeInvocation(Object object) { 31 | 32 | boolean permitAll = false; 33 | HttpServletRequest request = ((FilterInvocation) object).getRequest(); 34 | for(RequestMatcher requestMatcher : permitAllRequestMatchers){ 35 | if(requestMatcher.matches(request)){ 36 | permitAll = true; 37 | break; 38 | } 39 | } 40 | 41 | if(permitAll){ 42 | return null; 43 | } 44 | 45 | return super.beforeInvocation(object); 46 | } 47 | 48 | public void invoke(FilterInvocation fi) throws IOException, ServletException { 49 | if ((fi.getRequest() != null) 50 | && (fi.getRequest().getAttribute(FILTER_APPLIED) != null) 51 | && observeOncePerRequest) { 52 | // filter already applied to this request and user wants us to observe 53 | // once-per-request handling, so don't re-do security checking 54 | fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); 55 | } 56 | else { 57 | // first time this request being called, so perform security checking 58 | if (fi.getRequest() != null && observeOncePerRequest) { 59 | fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE); 60 | } 61 | 62 | InterceptorStatusToken token = beforeInvocation(fi); 63 | 64 | try { 65 | fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); 66 | } 67 | finally { 68 | super.finallyInvocation(token); 69 | } 70 | 71 | super.afterInvocation(token, null); 72 | } 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/handler/AjaxAccessDeniedHandler.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.handler; 2 | 3 | import org.springframework.security.access.AccessDeniedException; 4 | import org.springframework.security.web.access.AccessDeniedHandler; 5 | 6 | import javax.servlet.ServletException; 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletResponse; 9 | import java.io.IOException; 10 | 11 | public class AjaxAccessDeniedHandler implements AccessDeniedHandler { 12 | @Override 13 | public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) 14 | throws IOException, ServletException { 15 | 16 | response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access is denied"); 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/handler/AjaxAuthenticationFailureHandler.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.handler; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.http.MediaType; 8 | import org.springframework.security.authentication.BadCredentialsException; 9 | import org.springframework.security.authentication.CredentialsExpiredException; 10 | import org.springframework.security.authentication.DisabledException; 11 | import org.springframework.security.core.AuthenticationException; 12 | import org.springframework.security.web.authentication.AuthenticationFailureHandler; 13 | import org.springframework.stereotype.Component; 14 | 15 | import javax.servlet.ServletException; 16 | import javax.servlet.http.HttpServletRequest; 17 | import javax.servlet.http.HttpServletResponse; 18 | import java.io.IOException; 19 | 20 | public class AjaxAuthenticationFailureHandler implements AuthenticationFailureHandler { 21 | 22 | private ObjectMapper mapper = new ObjectMapper(); 23 | 24 | @Override 25 | public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { 26 | 27 | String errorMessage = "Invalid Username or Password"; 28 | 29 | response.setStatus(HttpStatus.UNAUTHORIZED.value()); 30 | response.setContentType(MediaType.APPLICATION_JSON_VALUE); 31 | 32 | if(exception instanceof BadCredentialsException) { 33 | errorMessage = "Invalid Username or Password"; 34 | } else if(exception instanceof DisabledException) { 35 | errorMessage = "Locked"; 36 | } else if(exception instanceof CredentialsExpiredException) { 37 | errorMessage = "Expired password"; 38 | } 39 | 40 | mapper.writeValue(response.getWriter(), errorMessage); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/handler/AjaxAuthenticationSuccessHandler.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.handler; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import io.security.corespringsecurity.domain.entity.Account; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.http.MediaType; 8 | import org.springframework.security.core.Authentication; 9 | import org.springframework.security.core.context.SecurityContextHolder; 10 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler; 11 | import org.springframework.security.web.context.HttpSessionSecurityContextRepository; 12 | 13 | import javax.servlet.ServletException; 14 | import javax.servlet.http.HttpServletRequest; 15 | import javax.servlet.http.HttpServletResponse; 16 | import javax.servlet.http.HttpSession; 17 | import java.io.IOException; 18 | 19 | public class AjaxAuthenticationSuccessHandler implements AuthenticationSuccessHandler { 20 | 21 | private final ObjectMapper mapper = new ObjectMapper(); 22 | 23 | @Override 24 | public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, 25 | Authentication authentication) throws IOException, ServletException { 26 | Account account = (Account) authentication.getPrincipal(); 27 | 28 | response.setStatus(HttpStatus.OK.value()); 29 | response.setContentType(MediaType.APPLICATION_JSON_VALUE); 30 | 31 | // HttpSession session = request.getSession(); 32 | // session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext()); 33 | 34 | mapper.writeValue(response.getWriter(), account); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/handler/FormAccessDeniedHandler.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.handler; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import io.security.corespringsecurity.util.WebUtil; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.http.MediaType; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.security.access.AccessDeniedException; 9 | import org.springframework.security.web.DefaultRedirectStrategy; 10 | import org.springframework.security.web.RedirectStrategy; 11 | import org.springframework.security.web.access.AccessDeniedHandler; 12 | import org.springframework.stereotype.Component; 13 | 14 | import javax.servlet.ServletException; 15 | import javax.servlet.http.HttpServletRequest; 16 | import javax.servlet.http.HttpServletResponse; 17 | import java.io.IOException; 18 | 19 | @Component 20 | public class FormAccessDeniedHandler implements AccessDeniedHandler { 21 | 22 | private String errorPage; 23 | 24 | private ObjectMapper mapper = new ObjectMapper(); 25 | 26 | private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); 27 | 28 | @Override 29 | public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { 30 | 31 | if (WebUtil.isAjax(request)) { 32 | response.setContentType(MediaType.APPLICATION_JSON_VALUE); 33 | response.getWriter().write(this.mapper.writeValueAsString(ResponseEntity.status(HttpStatus.FORBIDDEN))); 34 | 35 | } else { 36 | String deniedUrl = errorPage + "?exception=" + accessDeniedException.getMessage(); 37 | redirectStrategy.sendRedirect(request, response, deniedUrl); 38 | } 39 | } 40 | 41 | public void setErrorPage(String errorPage) { 42 | if ((errorPage != null) && !errorPage.startsWith("/")) { 43 | throw new IllegalArgumentException("errorPage must begin with '/'"); 44 | } 45 | 46 | this.errorPage = errorPage; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/handler/FormAuthenticationFailureHandler.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.handler; 2 | 3 | import org.springframework.security.authentication.BadCredentialsException; 4 | import org.springframework.security.authentication.CredentialsExpiredException; 5 | import org.springframework.security.authentication.DisabledException; 6 | import org.springframework.security.core.AuthenticationException; 7 | import org.springframework.security.web.DefaultRedirectStrategy; 8 | import org.springframework.security.web.RedirectStrategy; 9 | import org.springframework.security.web.WebAttributes; 10 | import org.springframework.security.web.authentication.AuthenticationFailureHandler; 11 | import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; 12 | import org.springframework.stereotype.Component; 13 | 14 | import javax.servlet.ServletException; 15 | import javax.servlet.http.HttpServletRequest; 16 | import javax.servlet.http.HttpServletResponse; 17 | import java.io.IOException; 18 | 19 | @Component 20 | public class FormAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { 21 | 22 | private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); 23 | 24 | @Override 25 | public void onAuthenticationFailure(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException exception) throws IOException, ServletException { 26 | 27 | String errorMessage = "Invalid Username or Password"; 28 | 29 | if(exception instanceof BadCredentialsException) { 30 | errorMessage = "Invalid Username or Password"; 31 | } else if(exception instanceof DisabledException) { 32 | errorMessage = "Locked"; 33 | } else if(exception instanceof CredentialsExpiredException) { 34 | errorMessage = "Expired password"; 35 | } 36 | 37 | setDefaultFailureUrl("/login?error=true&exception=" + errorMessage); 38 | 39 | super.onAuthenticationFailure(request, response, exception); 40 | 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/handler/FormAuthenticationSuccessHandler.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.handler; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.security.core.Authentication; 5 | import org.springframework.security.web.DefaultRedirectStrategy; 6 | import org.springframework.security.web.RedirectStrategy; 7 | import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; 8 | import org.springframework.security.web.savedrequest.HttpSessionRequestCache; 9 | import org.springframework.security.web.savedrequest.RequestCache; 10 | import org.springframework.security.web.savedrequest.SavedRequest; 11 | import org.springframework.stereotype.Component; 12 | 13 | import javax.servlet.http.HttpServletRequest; 14 | import javax.servlet.http.HttpServletResponse; 15 | import java.io.IOException; 16 | 17 | @Component 18 | @Slf4j 19 | public class FormAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { 20 | 21 | private RequestCache requestCache = new HttpSessionRequestCache(); 22 | 23 | private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); 24 | 25 | @Override 26 | public void onAuthenticationSuccess(final HttpServletRequest request, final HttpServletResponse response, final Authentication authentication) throws IOException { 27 | 28 | setDefaultTargetUrl("/"); 29 | 30 | SavedRequest savedRequest = requestCache.getRequest(request, response); 31 | 32 | if(savedRequest!=null) { 33 | String targetUrl = savedRequest.getRedirectUrl(); 34 | redirectStrategy.sendRedirect(request, response, targetUrl); 35 | } else { 36 | redirectStrategy.sendRedirect(request, response, getDefaultTargetUrl()); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/init/SecurityInitializer.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.init; 2 | 3 | import io.security.corespringsecurity.service.RoleHierarchyService; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.boot.ApplicationArguments; 6 | import org.springframework.boot.ApplicationRunner; 7 | import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | public class SecurityInitializer implements ApplicationRunner { 12 | 13 | @Autowired 14 | private RoleHierarchyService roleHierarchyService; 15 | 16 | @Autowired 17 | private RoleHierarchyImpl roleHierarchy; 18 | 19 | @Override 20 | public void run(ApplicationArguments args) throws Exception { 21 | String allHierarchy = roleHierarchyService.findAllHierarchy(); 22 | roleHierarchy.setHierarchy(allHierarchy); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/interceptor/CustomMethodSecurityInterceptor.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.interceptor; 2 | 3 | import org.aopalliance.intercept.MethodInterceptor; 4 | import org.aopalliance.intercept.MethodInvocation; 5 | import org.springframework.security.access.SecurityMetadataSource; 6 | import org.springframework.security.access.intercept.AbstractSecurityInterceptor; 7 | import org.springframework.security.access.intercept.InterceptorStatusToken; 8 | import org.springframework.security.access.method.MethodSecurityMetadataSource; 9 | 10 | public class CustomMethodSecurityInterceptor extends AbstractSecurityInterceptor implements 11 | MethodInterceptor { 12 | private MethodSecurityMetadataSource securityMetadataSource; 13 | 14 | public Class getSecureObjectClass() { 15 | return MethodInvocation.class; 16 | } 17 | 18 | public Object invoke(MethodInvocation mi) throws Throwable { 19 | InterceptorStatusToken token = super.beforeInvocation(mi); 20 | 21 | Object result; 22 | try { 23 | result = mi.proceed(); 24 | } 25 | finally { 26 | super.finallyInvocation(token); 27 | } 28 | return super.afterInvocation(token, result); 29 | } 30 | 31 | public MethodSecurityMetadataSource getSecurityMetadataSource() { 32 | return this.securityMetadataSource; 33 | } 34 | 35 | public SecurityMetadataSource obtainSecurityMetadataSource() { 36 | return this.securityMetadataSource; 37 | } 38 | 39 | public void setSecurityMetadataSource(MethodSecurityMetadataSource newSource) { 40 | this.securityMetadataSource = newSource; 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/listener/SetupDataLoader.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.listener; 2 | 3 | import io.security.corespringsecurity.domain.entity.*; 4 | import io.security.corespringsecurity.repository.*; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.ApplicationListener; 7 | import org.springframework.context.event.ContextRefreshedEvent; 8 | import org.springframework.security.crypto.password.PasswordEncoder; 9 | import org.springframework.stereotype.Component; 10 | import org.springframework.transaction.annotation.Transactional; 11 | 12 | import java.util.HashSet; 13 | import java.util.Set; 14 | import java.util.concurrent.atomic.AtomicInteger; 15 | 16 | @Component 17 | public class SetupDataLoader implements ApplicationListener { 18 | 19 | private boolean alreadySetup = false; 20 | 21 | @Autowired 22 | private UserRepository userRepository; 23 | 24 | @Autowired 25 | private RoleRepository roleRepository; 26 | 27 | @Autowired 28 | private ResourcesRepository resourcesRepository; 29 | 30 | @Autowired 31 | private RoleHierarchyRepository roleHierarchyRepository; 32 | 33 | @Autowired 34 | private PasswordEncoder passwordEncoder; 35 | 36 | @Autowired 37 | private AccessIpRepository accessIpRepository; 38 | 39 | private static AtomicInteger count = new AtomicInteger(0); 40 | 41 | @Override 42 | @Transactional 43 | public void onApplicationEvent(final ContextRefreshedEvent event) { 44 | 45 | if (alreadySetup) { 46 | return; 47 | } 48 | 49 | setupSecurityResources(); 50 | 51 | setupAccessIpData(); 52 | 53 | alreadySetup = true; 54 | } 55 | 56 | private void setupSecurityResources() { 57 | Set roles = new HashSet<>(); 58 | Role adminRole = createRoleIfNotFound("ROLE_ADMIN", "관리자"); 59 | roles.add(adminRole); 60 | createResourceIfNotFound("/admin/**", "", roles, "url"); 61 | createResourceIfNotFound("execution(public * io.security.corespringsecurity.aopsecurity.*Service.pointcut*(..))", "", roles, "pointcut"); 62 | createUserIfNotFound("admin", "admin@admin.com", "pass", roles); 63 | Role managerRole = createRoleIfNotFound("ROLE_MANAGER", "매니저권한"); 64 | Role userRole = createRoleIfNotFound("ROLE_USER", "사용자권한"); 65 | createRoleHierarchyIfNotFound(managerRole, adminRole); 66 | createRoleHierarchyIfNotFound(userRole, managerRole); 67 | } 68 | 69 | @Transactional 70 | public Role createRoleIfNotFound(String roleName, String roleDesc) { 71 | 72 | Role role = roleRepository.findByRoleName(roleName); 73 | 74 | if (role == null) { 75 | role = Role.builder() 76 | .roleName(roleName) 77 | .roleDesc(roleDesc) 78 | .build(); 79 | } 80 | return roleRepository.save(role); 81 | } 82 | 83 | @Transactional 84 | public Account createUserIfNotFound(final String userName, final String email, final String password, Set roleSet) { 85 | 86 | Account account = userRepository.findByUsername(userName); 87 | 88 | if (account == null) { 89 | account = Account.builder() 90 | .username(userName) 91 | .email(email) 92 | .password(passwordEncoder.encode(password)) 93 | .userRoles(roleSet) 94 | .build(); 95 | } 96 | return userRepository.save(account); 97 | } 98 | 99 | @Transactional 100 | public Resources createResourceIfNotFound(String resourceName, String httpMethod, Set roleSet, String resourceType) { 101 | Resources resources = resourcesRepository.findByResourceNameAndHttpMethod(resourceName, httpMethod); 102 | 103 | if (resources == null) { 104 | resources = Resources.builder() 105 | .resourceName(resourceName) 106 | .roleSet(roleSet) 107 | .httpMethod(httpMethod) 108 | .resourceType(resourceType) 109 | .orderNum(count.incrementAndGet()) 110 | .build(); 111 | } 112 | return resourcesRepository.save(resources); 113 | } 114 | 115 | @Transactional 116 | public void createRoleHierarchyIfNotFound(Role childRole, Role parentRole) { 117 | 118 | RoleHierarchy roleHierarchy = roleHierarchyRepository.findByChildName(parentRole.getRoleName()); 119 | if (roleHierarchy == null) { 120 | roleHierarchy = RoleHierarchy.builder() 121 | .childName(parentRole.getRoleName()) 122 | .build(); 123 | } 124 | RoleHierarchy parentRoleHierarchy = roleHierarchyRepository.save(roleHierarchy); 125 | 126 | roleHierarchy = roleHierarchyRepository.findByChildName(childRole.getRoleName()); 127 | if (roleHierarchy == null) { 128 | roleHierarchy = RoleHierarchy.builder() 129 | .childName(childRole.getRoleName()) 130 | .build(); 131 | } 132 | 133 | RoleHierarchy childRoleHierarchy = roleHierarchyRepository.save(roleHierarchy); 134 | childRoleHierarchy.setParentName(parentRoleHierarchy); 135 | } 136 | 137 | private void setupAccessIpData() { 138 | 139 | AccessIp byIpAddress = accessIpRepository.findByIpAddress("0:0:0:0:0:0:0:1"); 140 | if (byIpAddress == null) { 141 | AccessIp accessIp = AccessIp.builder() 142 | .ipAddress("0:0:0:0:0:0:0:1") 143 | .build(); 144 | accessIpRepository.save(accessIp); 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/metadatasource/UrlFilterInvocationSecurityMetadataSource.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.metadatasource; 2 | 3 | import io.security.corespringsecurity.service.SecurityResourceService; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.security.access.ConfigAttribute; 6 | import org.springframework.security.web.FilterInvocation; 7 | import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; 8 | import org.springframework.security.web.util.matcher.RequestMatcher; 9 | 10 | import javax.servlet.http.HttpServletRequest; 11 | import java.util.*; 12 | 13 | @Slf4j 14 | public class UrlFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { 15 | 16 | private LinkedHashMap> requestMap ; 17 | 18 | private SecurityResourceService securityResourceService; 19 | 20 | public UrlFilterInvocationSecurityMetadataSource(LinkedHashMap> resourcesMap, SecurityResourceService securityResourceService) { 21 | this.requestMap = resourcesMap; 22 | this.securityResourceService = securityResourceService; 23 | } 24 | 25 | @Override 26 | public Collection getAttributes(Object object) throws IllegalArgumentException { 27 | 28 | HttpServletRequest request = ((FilterInvocation) object).getRequest(); 29 | 30 | if(requestMap != null){ 31 | for(Map.Entry> entry : requestMap.entrySet()){ 32 | RequestMatcher matcher = entry.getKey(); 33 | if(matcher.matches(request)){ 34 | return entry.getValue(); 35 | } 36 | } 37 | } 38 | 39 | return null; 40 | } 41 | 42 | @Override 43 | public Collection getAllConfigAttributes() { 44 | Set allAttributes = new HashSet<>(); 45 | 46 | for (Map.Entry> entry : requestMap 47 | .entrySet()) { 48 | allAttributes.addAll(entry.getValue()); 49 | } 50 | 51 | return allAttributes; 52 | } 53 | 54 | @Override 55 | public boolean supports(Class clazz) { 56 | return FilterInvocation.class.isAssignableFrom(clazz); 57 | } 58 | 59 | public void reload(){ 60 | 61 | LinkedHashMap> reloadedMap = securityResourceService.getResourceList(); 62 | Iterator>> iterator = reloadedMap.entrySet().iterator(); 63 | 64 | requestMap.clear(); 65 | 66 | while(iterator.hasNext()){ 67 | Map.Entry> entry = iterator.next(); 68 | requestMap.put(entry.getKey(), entry.getValue()); 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/processor/ProtectPointcutPostProcessor.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.processor; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.aspectj.weaver.tools.PointcutExpression; 5 | import org.aspectj.weaver.tools.PointcutParser; 6 | import org.aspectj.weaver.tools.PointcutPrimitive; 7 | import org.springframework.beans.BeansException; 8 | import org.springframework.beans.factory.config.BeanPostProcessor; 9 | import org.springframework.security.access.ConfigAttribute; 10 | import org.springframework.security.access.method.MapBasedMethodSecurityMetadataSource; 11 | import org.springframework.util.Assert; 12 | import org.springframework.util.StringUtils; 13 | 14 | import java.lang.reflect.Method; 15 | import java.util.*; 16 | 17 | @Slf4j 18 | public class ProtectPointcutPostProcessor implements BeanPostProcessor { 19 | 20 | private final Map> pointcutMap = new LinkedHashMap>(); 21 | private final MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource; 22 | private final Set pointCutExpressions = new LinkedHashSet<>(); 23 | private final PointcutParser parser; 24 | private final Set processedBeans = new HashSet<>(); 25 | 26 | public ProtectPointcutPostProcessor(MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource) { 27 | Assert.notNull(mapBasedMethodSecurityMetadataSource, "MapBasedMethodSecurityMetadataSource to populate is required"); 28 | this.mapBasedMethodSecurityMetadataSource = mapBasedMethodSecurityMetadataSource; 29 | 30 | Set supportedPrimitives = new HashSet<>(3); 31 | supportedPrimitives.add(PointcutPrimitive.EXECUTION); 32 | supportedPrimitives.add(PointcutPrimitive.ARGS); 33 | supportedPrimitives.add(PointcutPrimitive.REFERENCE); 34 | parser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(supportedPrimitives); 35 | } 36 | 37 | public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 38 | return bean; 39 | } 40 | 41 | public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 42 | 43 | if (processedBeans.contains(beanName)) { 44 | return bean; 45 | } 46 | 47 | synchronized (processedBeans) { 48 | if (processedBeans.contains(beanName)) { 49 | return bean; 50 | } 51 | 52 | Method[] methods; 53 | try { 54 | methods = bean.getClass().getMethods(); 55 | } catch (Exception e) { 56 | throw new IllegalStateException(e.getMessage()); 57 | } 58 | 59 | for (Method method : methods) { 60 | for (PointcutExpression expression : pointCutExpressions) { 61 | if (attemptMatch(bean.getClass(), method, expression, beanName)) { 62 | break; 63 | } 64 | } 65 | } 66 | 67 | processedBeans.add(beanName); 68 | } 69 | 70 | return bean; 71 | } 72 | 73 | /** 74 | * 설정클래스에서 람다 형식으로 선언된 빈이 존재할 경우 에러가 발생하여 스프링 빈과 동일한 클래스를 생성하여 약간 수정함 75 | * 아직 AspectJ 라이브러리에서 Fix 하지 못한 것으로 판단되지만 다른 원인이 존재하는지 계속 살펴보도록 함 76 | */ 77 | private boolean attemptMatch(Class targetClass, Method method, PointcutExpression expression, String beanName) { 78 | 79 | boolean matches; 80 | try { 81 | matches = expression.matchesMethodExecution(method).alwaysMatches(); 82 | if (matches) { 83 | List attr = pointcutMap.get(expression.getPointcutExpression()); 84 | 85 | if (log.isDebugEnabled()) { 86 | log.debug("AspectJ pointcut expression '" 87 | + expression.getPointcutExpression() + "' matches target class '" 88 | + targetClass.getName() + "' (bean ID '" + beanName 89 | + "') for method '" + method 90 | + "'; registering security configuration attribute '" + attr 91 | + "'"); 92 | } 93 | 94 | mapBasedMethodSecurityMetadataSource.addSecureMethod(targetClass, method, attr); 95 | } 96 | return matches; 97 | 98 | } catch (Exception e) { 99 | matches = false; 100 | } 101 | return matches; 102 | } 103 | 104 | public void setPointcutMap(Map> map) { 105 | Assert.notEmpty(map, "configAttributes cannot be empty"); 106 | for (String expression : map.keySet()) { 107 | List value = map.get(expression); 108 | addPointcut(expression, value); 109 | } 110 | } 111 | 112 | private void addPointcut(String pointcutExpression, List definition) { 113 | Assert.hasText(pointcutExpression, "An AspectJ pointcut expression is required"); 114 | Assert.notNull(definition, "A List of ConfigAttributes is required"); 115 | pointcutExpression = replaceBooleanOperators(pointcutExpression); 116 | pointcutMap.put(pointcutExpression, definition); 117 | pointCutExpressions.add(parser.parsePointcutExpression(pointcutExpression)); 118 | 119 | if (log.isDebugEnabled()) { 120 | log.debug("AspectJ pointcut expression '" + pointcutExpression 121 | + "' registered for security configuration attribute '" + definition 122 | + "'"); 123 | } 124 | } 125 | 126 | private String replaceBooleanOperators(String pcExpr) { 127 | pcExpr = StringUtils.replace(pcExpr, " and ", " && "); 128 | pcExpr = StringUtils.replace(pcExpr, " or ", " || "); 129 | pcExpr = StringUtils.replace(pcExpr, " not ", " ! "); 130 | return pcExpr; 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/provider/AjaxAuthenticationProvider.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.provider; 2 | 3 | import io.security.corespringsecurity.security.service.AccountContext; 4 | import io.security.corespringsecurity.security.token.AjaxAuthenticationToken; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.security.authentication.AuthenticationProvider; 8 | import org.springframework.security.authentication.BadCredentialsException; 9 | import org.springframework.security.core.Authentication; 10 | import org.springframework.security.core.AuthenticationException; 11 | import org.springframework.security.core.userdetails.UserDetailsService; 12 | import org.springframework.security.crypto.password.PasswordEncoder; 13 | 14 | import javax.transaction.Transactional; 15 | 16 | @Slf4j 17 | public class AjaxAuthenticationProvider implements AuthenticationProvider { 18 | 19 | @Autowired 20 | private UserDetailsService userDetailsService; 21 | 22 | @Autowired 23 | PasswordEncoder passwordEncoder; 24 | 25 | @Override 26 | @Transactional 27 | public Authentication authenticate(Authentication authentication) throws AuthenticationException { 28 | 29 | String loginId = authentication.getName(); 30 | String password = (String) authentication.getCredentials(); 31 | 32 | AccountContext accountContext = (AccountContext)userDetailsService.loadUserByUsername(loginId); 33 | 34 | if (!passwordEncoder.matches(password, accountContext.getPassword())) { 35 | throw new BadCredentialsException("Invalid password"); 36 | } 37 | 38 | return new AjaxAuthenticationToken(accountContext.getAccount(), null, accountContext.getAuthorities()); 39 | } 40 | 41 | @Override 42 | public boolean supports(Class authentication) { 43 | return authentication.equals(AjaxAuthenticationToken.class); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/provider/FormAuthenticationProvider.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.provider; 2 | 3 | import io.security.corespringsecurity.security.common.FormWebAuthenticationDetails; 4 | import io.security.corespringsecurity.security.service.AccountContext; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.security.authentication.AuthenticationProvider; 8 | import org.springframework.security.authentication.BadCredentialsException; 9 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 10 | import org.springframework.security.core.Authentication; 11 | import org.springframework.security.core.AuthenticationException; 12 | import org.springframework.security.core.userdetails.UserDetailsService; 13 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 14 | import org.springframework.security.crypto.password.PasswordEncoder; 15 | import org.springframework.stereotype.Component; 16 | 17 | import javax.transaction.Transactional; 18 | 19 | @Slf4j 20 | public class FormAuthenticationProvider implements AuthenticationProvider { 21 | 22 | @Autowired 23 | private UserDetailsService userDetailsService; 24 | 25 | private PasswordEncoder passwordEncoder; 26 | 27 | public FormAuthenticationProvider(PasswordEncoder passwordEncoder) { 28 | this.passwordEncoder = passwordEncoder; 29 | } 30 | 31 | @Override 32 | @Transactional 33 | public Authentication authenticate(Authentication authentication) throws AuthenticationException { 34 | 35 | String loginId = authentication.getName(); 36 | String password = (String) authentication.getCredentials(); 37 | 38 | AccountContext accountContext = (AccountContext)userDetailsService.loadUserByUsername(loginId); 39 | 40 | if (!passwordEncoder.matches(password, accountContext.getPassword())) { 41 | throw new BadCredentialsException("Invalid password"); 42 | } 43 | 44 | String secretKey = ((FormWebAuthenticationDetails) authentication.getDetails()).getSecretKey(); 45 | if (secretKey == null || !secretKey.equals("secret")) { 46 | throw new IllegalArgumentException("Invalid Secret"); 47 | } 48 | 49 | return new UsernamePasswordAuthenticationToken(accountContext.getAccount(), null, accountContext.getAuthorities()); 50 | } 51 | 52 | @Override 53 | public boolean supports(Class authentication) { 54 | return authentication.equals(UsernamePasswordAuthenticationToken.class); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/service/AccountContext.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.service; 2 | 3 | import io.security.corespringsecurity.domain.entity.Account; 4 | import lombok.Data; 5 | import org.springframework.security.core.GrantedAuthority; 6 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 7 | import org.springframework.security.core.userdetails.User; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.List; 12 | import java.util.stream.Collectors; 13 | 14 | @Data 15 | public class AccountContext extends User { 16 | private Account account; 17 | 18 | public AccountContext(Account account, List roles) { 19 | super(account.getUsername(), account.getPassword(), roles); 20 | this.account = account; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/service/UserDetailsServiceImpl.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.service; 2 | 3 | import io.security.corespringsecurity.domain.entity.Account; 4 | import io.security.corespringsecurity.repository.UserRepository; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.security.core.GrantedAuthority; 8 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 9 | import org.springframework.security.core.userdetails.UserDetails; 10 | import org.springframework.security.core.userdetails.UserDetailsService; 11 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 12 | import org.springframework.stereotype.Service; 13 | 14 | import javax.servlet.http.HttpServletRequest; 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.Set; 18 | import java.util.stream.Collectors; 19 | 20 | @Slf4j 21 | @Service("userDetailsService") 22 | public class UserDetailsServiceImpl implements UserDetailsService { 23 | 24 | @Autowired 25 | private UserRepository userRepository; 26 | 27 | @Autowired 28 | private HttpServletRequest request; 29 | 30 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 31 | 32 | Account account = userRepository.findByUsername(username); 33 | if (account == null) { 34 | if (userRepository.countByUsername(username) == 0) { 35 | throw new UsernameNotFoundException("No user found with username: " + username); 36 | } 37 | } 38 | Set userRoles = account.getUserRoles() 39 | .stream() 40 | .map(userRole -> userRole.getRoleName()) 41 | .collect(Collectors.toSet()); 42 | 43 | List collect = userRoles.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()); 44 | return new AccountContext(account, collect); 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/token/AjaxAuthenticationToken.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.token; 2 | 3 | import org.springframework.security.authentication.AbstractAuthenticationToken; 4 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 5 | import org.springframework.security.core.GrantedAuthority; 6 | 7 | import java.util.Collection; 8 | 9 | public class AjaxAuthenticationToken extends AbstractAuthenticationToken { 10 | 11 | private final Object principal; 12 | private Object credentials; 13 | 14 | public AjaxAuthenticationToken(Object principal, Object credentials) { 15 | super(null); 16 | this.principal = principal; 17 | this.credentials = credentials; 18 | setAuthenticated(false); 19 | } 20 | 21 | public AjaxAuthenticationToken(Object principal, Object credentials, Collection authorities) { 22 | super(authorities); 23 | this.principal = principal; 24 | this.credentials = credentials; 25 | super.setAuthenticated(true); 26 | } 27 | 28 | @Override 29 | public Object getCredentials() { 30 | return this.credentials; 31 | } 32 | 33 | @Override 34 | public Object getPrincipal() { 35 | return this.principal; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/security/voter/IpAddressVoter.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.security.voter; 2 | 3 | import io.security.corespringsecurity.service.SecurityResourceService; 4 | import org.springframework.security.access.AccessDecisionVoter; 5 | import org.springframework.security.access.AccessDeniedException; 6 | import org.springframework.security.access.ConfigAttribute; 7 | import org.springframework.security.core.Authentication; 8 | import org.springframework.security.web.authentication.WebAuthenticationDetails; 9 | 10 | import java.util.Collection; 11 | import java.util.List; 12 | 13 | public class IpAddressVoter implements AccessDecisionVoter { 14 | 15 | private SecurityResourceService securityResourceService; 16 | 17 | public IpAddressVoter(SecurityResourceService securityResourceService) { 18 | 19 | this.securityResourceService = securityResourceService; 20 | } 21 | 22 | @Override 23 | public boolean supports(ConfigAttribute attribute) { 24 | return true; 25 | } 26 | 27 | @Override 28 | public boolean supports(Class clazz) { 29 | return true; 30 | } 31 | 32 | @Override 33 | public int vote(Authentication authentication, Object object, Collection attributes) { 34 | 35 | WebAuthenticationDetails details = (WebAuthenticationDetails)authentication.getDetails(); 36 | String remoteAddress = details.getRemoteAddress(); 37 | 38 | List accessIpList = securityResourceService.getAccessIpList(); 39 | 40 | int result = ACCESS_DENIED; 41 | 42 | for(String ipAddress : accessIpList){ 43 | if(remoteAddress.equals(ipAddress)){ 44 | return ACCESS_ABSTAIN; 45 | } 46 | } 47 | 48 | if(result == ACCESS_DENIED){ 49 | throw new AccessDeniedException("Invalid IpAddress"); 50 | } 51 | 52 | return result; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/service/MethodSecurityService.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.service; 2 | 3 | import io.security.corespringsecurity.security.interceptor.CustomMethodSecurityInterceptor; 4 | import org.springframework.aop.framework.ProxyFactory; 5 | import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry; 6 | import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext; 7 | import org.springframework.security.access.ConfigAttribute; 8 | import org.springframework.security.access.SecurityConfig; 9 | import org.springframework.security.access.method.MapBasedMethodSecurityMetadataSource; 10 | import org.springframework.stereotype.Component; 11 | import org.springframework.util.ClassUtils; 12 | 13 | import java.util.Arrays; 14 | import java.util.HashMap; 15 | import java.util.List; 16 | import java.util.Map; 17 | 18 | @Component 19 | public class MethodSecurityService { 20 | 21 | private MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource; 22 | private AnnotationConfigServletWebServerApplicationContext applicationContext; 23 | private CustomMethodSecurityInterceptor methodSecurityInterceptor; 24 | 25 | private Map proxyMap = new HashMap<>(); 26 | private Map advisedMap = new HashMap<>(); 27 | private Map targetMap = new HashMap<>(); 28 | 29 | public MethodSecurityService(MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource, AnnotationConfigServletWebServerApplicationContext applicationContext, CustomMethodSecurityInterceptor methodSecurityInterceptor) { 30 | this.mapBasedMethodSecurityMetadataSource = mapBasedMethodSecurityMetadataSource; 31 | this.applicationContext = applicationContext; 32 | this.methodSecurityInterceptor = methodSecurityInterceptor; 33 | } 34 | 35 | public void addMethodSecured(String className, String roleName) throws Exception{ 36 | 37 | int lastDotIndex = className.lastIndexOf("."); 38 | String methodName = className.substring(lastDotIndex + 1); 39 | String typeName = className.substring(0, lastDotIndex); 40 | Class type = ClassUtils.resolveClassName(typeName, ClassUtils.getDefaultClassLoader()); 41 | String beanName = type.getSimpleName().substring(0, 1).toLowerCase() + type.getSimpleName().substring(1); 42 | 43 | ProxyFactory proxyFactory = advisedMap.get(beanName); 44 | Object target = targetMap.get(beanName); 45 | 46 | if(proxyFactory == null){ 47 | 48 | proxyFactory = new ProxyFactory(); 49 | if(target == null) { 50 | proxyFactory.setTarget(type.getDeclaredConstructor().newInstance()); 51 | 52 | }else{ 53 | proxyFactory.setTarget(target); 54 | } 55 | proxyFactory.addAdvice(methodSecurityInterceptor); 56 | 57 | advisedMap.put(beanName, proxyFactory); 58 | 59 | }else{ 60 | 61 | int adviceIndex = proxyFactory.indexOf(methodSecurityInterceptor); 62 | if(adviceIndex == -1){ 63 | proxyFactory.addAdvice(methodSecurityInterceptor); 64 | } 65 | } 66 | 67 | Object proxy = proxyMap.get(beanName); 68 | 69 | if(proxy == null){ 70 | 71 | proxy = proxyFactory.getProxy(); 72 | proxyMap.put(beanName, proxy); 73 | 74 | List attr = Arrays.asList(new SecurityConfig(roleName)); 75 | mapBasedMethodSecurityMetadataSource.addSecureMethod(type,methodName, attr); 76 | 77 | DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry)applicationContext.getBeanFactory(); 78 | registry.destroySingleton(beanName); 79 | registry.registerSingleton(beanName, proxy); 80 | } 81 | } 82 | 83 | public void removeMethodSecured(String className) throws Exception{ 84 | 85 | int lastDotIndex = className.lastIndexOf("."); 86 | String typeName = className.substring(0, lastDotIndex); 87 | Class type = ClassUtils.resolveClassName(typeName, ClassUtils.getDefaultClassLoader()); 88 | String beanName = type.getSimpleName().substring(0, 1).toLowerCase() + type.getSimpleName().substring(1); 89 | Object newInstance = type.getDeclaredConstructor().newInstance(); 90 | 91 | DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry)applicationContext.getBeanFactory(); 92 | 93 | ProxyFactory proxyFactory = advisedMap.get(beanName); 94 | 95 | if(proxyFactory != null){ 96 | proxyFactory.removeAdvice(methodSecurityInterceptor); 97 | 98 | }else{ 99 | registry.destroySingleton(beanName); 100 | registry.registerSingleton(beanName, newInstance); 101 | targetMap.put(beanName,newInstance); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/service/ResourcesService.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.service; 2 | 3 | import io.security.corespringsecurity.domain.entity.Resources; 4 | 5 | import java.util.List; 6 | 7 | public interface ResourcesService { 8 | 9 | Resources getResources(long id); 10 | 11 | List getResources(); 12 | 13 | void createResources(Resources Resources); 14 | 15 | void deleteResources(long id); 16 | } -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/service/RoleHierarchyService.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.service; 2 | 3 | public interface RoleHierarchyService { 4 | 5 | String findAllHierarchy(); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/service/RoleService.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.service; 2 | 3 | import io.security.corespringsecurity.domain.entity.Role; 4 | 5 | import java.util.List; 6 | 7 | public interface RoleService { 8 | 9 | Role getRole(long id); 10 | 11 | List getRoles(); 12 | 13 | void createRole(Role role); 14 | 15 | void deleteRole(long id); 16 | } -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/service/SecurityResourceService.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.service; 2 | 3 | import io.security.corespringsecurity.domain.entity.Resources; 4 | import io.security.corespringsecurity.repository.AccessIpRepository; 5 | import io.security.corespringsecurity.repository.ResourcesRepository; 6 | import org.springframework.security.access.ConfigAttribute; 7 | import org.springframework.security.access.SecurityConfig; 8 | import org.springframework.security.web.util.matcher.AntPathRequestMatcher; 9 | import org.springframework.security.web.util.matcher.RequestMatcher; 10 | import org.springframework.stereotype.Service; 11 | 12 | import java.util.ArrayList; 13 | import java.util.LinkedHashMap; 14 | import java.util.List; 15 | import java.util.stream.Collectors; 16 | 17 | @Service 18 | public class SecurityResourceService { 19 | 20 | private ResourcesRepository resourcesRepository; 21 | private AccessIpRepository accessIpRepository; 22 | 23 | public SecurityResourceService(ResourcesRepository resourcesRepository, AccessIpRepository accessIpRepository) { 24 | this.resourcesRepository = resourcesRepository; 25 | this.accessIpRepository = accessIpRepository; 26 | } 27 | 28 | public LinkedHashMap> getResourceList(){ 29 | 30 | LinkedHashMap> result = new LinkedHashMap<>(); 31 | List resourcesList = resourcesRepository.findAllResources(); 32 | resourcesList.forEach(re ->{ 33 | List configAttributeList = new ArrayList<>(); 34 | re.getRoleSet().forEach(role -> { 35 | configAttributeList.add(new SecurityConfig(role.getRoleName())); 36 | }); 37 | result.put(new AntPathRequestMatcher(re.getResourceName()),configAttributeList); 38 | 39 | }); 40 | return result; 41 | } 42 | 43 | public LinkedHashMap> getMethodResourceList() { 44 | 45 | LinkedHashMap> result = new LinkedHashMap<>(); 46 | List resourcesList = resourcesRepository.findAllMethodResources(); 47 | resourcesList.forEach(re -> 48 | { 49 | List configAttributeList = new ArrayList<>(); 50 | re.getRoleSet().forEach(ro -> { 51 | configAttributeList.add(new SecurityConfig(ro.getRoleName())); 52 | }); 53 | result.put(re.getResourceName(), configAttributeList); 54 | } 55 | ); 56 | return result; 57 | } 58 | 59 | public LinkedHashMap> getPointcutResourceList() { 60 | 61 | LinkedHashMap> result = new LinkedHashMap<>(); 62 | List resourcesList = resourcesRepository.findAllPointcutResources(); 63 | resourcesList.forEach(re -> 64 | { 65 | List configAttributeList = new ArrayList<>(); 66 | re.getRoleSet().forEach(ro -> { 67 | configAttributeList.add(new SecurityConfig(ro.getRoleName())); 68 | }); 69 | result.put(re.getResourceName(), configAttributeList); 70 | } 71 | ); 72 | return result; 73 | } 74 | 75 | public List getAccessIpList() { 76 | List accessIpList = accessIpRepository.findAll().stream().map(accessIp -> accessIp.getIpAddress()).collect(Collectors.toList()); 77 | return accessIpList; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/service/UserService.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.service; 2 | 3 | import io.security.corespringsecurity.domain.dto.AccountDto; 4 | import io.security.corespringsecurity.domain.entity.Account; 5 | 6 | import java.util.List; 7 | 8 | public interface UserService { 9 | 10 | void createUser(Account account); 11 | 12 | void modifyUser(AccountDto accountDto); 13 | 14 | List getUsers(); 15 | 16 | AccountDto getUser(Long id); 17 | 18 | void deleteUser(Long idx); 19 | 20 | void order(); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/service/impl/ResourcesServiceImpl.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.service.impl; 2 | 3 | import io.security.corespringsecurity.domain.entity.Resources; 4 | import io.security.corespringsecurity.repository.ResourcesRepository; 5 | import io.security.corespringsecurity.service.ResourcesService; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.data.domain.Sort; 9 | import org.springframework.stereotype.Service; 10 | import org.springframework.transaction.annotation.Transactional; 11 | 12 | import java.util.List; 13 | 14 | @Slf4j 15 | @Service 16 | public class ResourcesServiceImpl implements ResourcesService { 17 | 18 | @Autowired 19 | private ResourcesRepository ResourcesRepository; 20 | 21 | @Transactional 22 | public Resources getResources(long id) { 23 | return ResourcesRepository.findById(id).orElse(new Resources()); 24 | } 25 | 26 | @Transactional 27 | public List getResources() { 28 | return ResourcesRepository.findAll(Sort.by(Sort.Order.asc("orderNum"))); 29 | } 30 | 31 | @Transactional 32 | public void createResources(Resources resources){ 33 | ResourcesRepository.save(resources); 34 | } 35 | 36 | @Transactional 37 | public void deleteResources(long id) { 38 | ResourcesRepository.deleteById(id); 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/service/impl/RoleHierarchyServiceImpl.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.service.impl; 2 | 3 | import io.security.corespringsecurity.domain.entity.RoleHierarchy; 4 | import io.security.corespringsecurity.repository.RoleHierarchyRepository; 5 | import io.security.corespringsecurity.service.RoleHierarchyService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | import org.springframework.transaction.annotation.Transactional; 9 | 10 | import java.util.Iterator; 11 | import java.util.List; 12 | 13 | @Service 14 | public class RoleHierarchyServiceImpl implements RoleHierarchyService { 15 | 16 | @Autowired 17 | private RoleHierarchyRepository roleHierarchyRepository; 18 | 19 | @Transactional 20 | @Override 21 | public String findAllHierarchy() { 22 | 23 | List rolesHierarchy = roleHierarchyRepository.findAll(); 24 | 25 | Iterator itr = rolesHierarchy.iterator(); 26 | StringBuilder concatedRoles = new StringBuilder(); 27 | while (itr.hasNext()) { 28 | RoleHierarchy roleHierarchy = itr.next(); 29 | if (roleHierarchy.getParentName() != null) { 30 | concatedRoles.append(roleHierarchy.getParentName().getChildName()); 31 | concatedRoles.append(" > "); 32 | concatedRoles.append(roleHierarchy.getChildName()); 33 | concatedRoles.append("\n"); 34 | } 35 | } 36 | return concatedRoles.toString(); 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/service/impl/RoleServiceImpl.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.service.impl; 2 | 3 | import io.security.corespringsecurity.domain.entity.Role; 4 | import io.security.corespringsecurity.repository.RoleRepository; 5 | import io.security.corespringsecurity.service.RoleService; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.transaction.annotation.Transactional; 10 | 11 | import java.util.List; 12 | 13 | @Slf4j 14 | @Service 15 | public class RoleServiceImpl implements RoleService { 16 | 17 | @Autowired 18 | private RoleRepository roleRepository; 19 | 20 | @Transactional 21 | public Role getRole(long id) { 22 | return roleRepository.findById(id).orElse(new Role()); 23 | } 24 | 25 | @Transactional 26 | public List getRoles() { 27 | 28 | return roleRepository.findAll(); 29 | } 30 | 31 | @Transactional 32 | public void createRole(Role role){ 33 | 34 | roleRepository.save(role); 35 | } 36 | 37 | @Transactional 38 | public void deleteRole(long id) { 39 | roleRepository.deleteById(id); 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/service/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.service.impl; 2 | 3 | import io.security.corespringsecurity.domain.dto.AccountDto; 4 | import io.security.corespringsecurity.domain.entity.Account; 5 | import io.security.corespringsecurity.domain.entity.Role; 6 | import io.security.corespringsecurity.repository.RoleRepository; 7 | import io.security.corespringsecurity.repository.UserRepository; 8 | import io.security.corespringsecurity.service.UserService; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.modelmapper.ModelMapper; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.security.access.annotation.Secured; 13 | import org.springframework.security.crypto.password.PasswordEncoder; 14 | import org.springframework.stereotype.Service; 15 | import org.springframework.transaction.annotation.Transactional; 16 | 17 | import java.util.HashSet; 18 | import java.util.List; 19 | import java.util.Optional; 20 | import java.util.Set; 21 | import java.util.stream.Collectors; 22 | 23 | @Slf4j 24 | @Service("userService") 25 | public class UserServiceImpl implements UserService { 26 | 27 | @Autowired 28 | private UserRepository userRepository; 29 | 30 | @Autowired 31 | private RoleRepository roleRepository; 32 | 33 | @Autowired 34 | private PasswordEncoder passwordEncoder; 35 | 36 | @Transactional 37 | @Override 38 | public void createUser(Account account){ 39 | 40 | Role role = roleRepository.findByRoleName("ROLE_USER"); 41 | Set roles = new HashSet<>(); 42 | roles.add(role); 43 | account.setUserRoles(roles); 44 | userRepository.save(account); 45 | } 46 | 47 | @Transactional 48 | @Override 49 | public void modifyUser(AccountDto accountDto){ 50 | 51 | ModelMapper modelMapper = new ModelMapper(); 52 | Account account = modelMapper.map(accountDto, Account.class); 53 | 54 | if(accountDto.getRoles() != null){ 55 | Set roles = new HashSet<>(); 56 | accountDto.getRoles().forEach(role -> { 57 | Role r = roleRepository.findByRoleName(role); 58 | roles.add(r); 59 | }); 60 | account.setUserRoles(roles); 61 | } 62 | account.setPassword(passwordEncoder.encode(accountDto.getPassword())); 63 | userRepository.save(account); 64 | 65 | } 66 | 67 | @Transactional 68 | public AccountDto getUser(Long id) { 69 | 70 | Account account = userRepository.findById(id).orElse(new Account()); 71 | ModelMapper modelMapper = new ModelMapper(); 72 | AccountDto accountDto = modelMapper.map(account, AccountDto.class); 73 | 74 | List roles = account.getUserRoles() 75 | .stream() 76 | .map(role -> role.getRoleName()) 77 | .collect(Collectors.toList()); 78 | 79 | accountDto.setRoles(roles); 80 | return accountDto; 81 | } 82 | 83 | @Transactional 84 | public List getUsers() { 85 | return userRepository.findAll(); 86 | } 87 | 88 | @Override 89 | public void deleteUser(Long id) { 90 | userRepository.deleteById(id); 91 | } 92 | 93 | @Override 94 | @Secured("ROLE_MANAGER") 95 | public void order() { 96 | System.out.println("order"); 97 | } 98 | } -------------------------------------------------------------------------------- /src/main/java/io/security/corespringsecurity/util/WebUtil.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity.util; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | 5 | public class WebUtil { 6 | private static final String XML_HTTP_REQUEST = "XMLHttpRequest"; 7 | private static final String X_REQUESTED_WITH = "X-Requested-With"; 8 | 9 | private static final String CONTENT_TYPE = "Content-type"; 10 | private static final String CONTENT_TYPE_JSON = "application/json"; 11 | 12 | public static boolean isAjax(HttpServletRequest request) { 13 | return XML_HTTP_REQUEST.equals(request.getHeader(X_REQUESTED_WITH)); 14 | } 15 | 16 | public static boolean isContentTypeJson(HttpServletRequest request) { 17 | return request.getHeader(CONTENT_TYPE).contains(CONTENT_TYPE_JSON); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.url=jdbc:postgresql://localhost:5432/springboot 2 | spring.datasource.username=postgres 3 | spring.datasource.password=pass 4 | 5 | spring.jpa.hibernate.ddl-auto=update 6 | spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect 7 | spring.jpa.properties.hibernate.format_sql=true 8 | spring.jpa.properties.hibernate.show_sql=true 9 | spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true 10 | 11 | spring.thymeleaf.cache=false 12 | 13 | spring.devtools.livereload.enabled=true 14 | spring.devtools.restart.enabled=true 15 | 16 | spring.main.allow-bean-definition-overriding=true 17 | 18 | #spring.profiles.active=pointcut -------------------------------------------------------------------------------- /src/main/resources/static/css/base.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | .cc-tab-con { padding: 5px 0 30px; overflow: hidden; } 4 | .cc-tab-item { display: block; position: relative; float: left; margin-left: -1px; padding: 0 10px; min-width: 180px; height: 50px; line-height: 50px; font-size: 16px; font-weight: bold; color: #7b7b7b; text-align: center; text-decoration: none !important; z-index: 5; border: 1px solid #d4d4d4; -webkit-transition: color 0.4s; transition: color 0.4s; } 5 | .cc-tab-item:first-child { margin-left: 0; } 6 | .cc-tab-item:hover { color: #ed3e64; } 7 | .cc-tab-item.on { cursor: default; line-height: 45px; color: #ed3e64; border-color: #ed3e64; border-bottom: 0 none; border-top-width: 5px; z-index: 8; } 8 | .security { 9 | height:200px; 10 | background-image: url("../images/springsecurity.jpg"); 11 | background-repeat: no-repeat; 12 | background-position: center; 13 | } 14 | 15 | .sidebar { 16 | position: fixed; 17 | top: 0; 18 | bottom: 0; 19 | left: 0; 20 | z-index: 100; /* Behind the navbar */ 21 | padding: 0; 22 | box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1); 23 | } 24 | 25 | .sidebar-sticky { 26 | position: -webkit-sticky; 27 | position: sticky; 28 | top: 48px; /* Height of navbar */ 29 | height: calc(50vh); 30 | padding-top: .5rem; 31 | overflow-x: hidden; 32 | overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ 33 | } 34 | 35 | .sidebar .nav-link { 36 | font-weight: 500; 37 | color: #333; 38 | } 39 | 40 | .sidebar .nav-link .feather { 41 | margin-right: 4px; 42 | color: #999; 43 | } 44 | 45 | .sidebar .nav-link.active { 46 | color: #007bff; 47 | } 48 | 49 | .sidebar .nav-link:hover .feather, 50 | .sidebar .nav-link.active .feather { 51 | color: inherit; 52 | } 53 | 54 | .sidebar-heading { 55 | font-size: .75rem; 56 | text-transform: uppercase; 57 | } 58 | .navbar-brand { 59 | padding-top: .75rem; 60 | padding-bottom: .75rem; 61 | font-size: 1rem; 62 | background-color: rgba(0, 0, 0, .25); 63 | box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25); 64 | } 65 | 66 | .navbar .form-control { 67 | padding: .75rem 1rem; 68 | border-width: 0; 69 | border-radius: 0; 70 | } 71 | 72 | .form-control-dark { 73 | color: #fff; 74 | background-color: rgba(255, 255, 255, .1); 75 | border-color: rgba(255, 255, 255, .1); 76 | } 77 | 78 | .form-control-dark:focus { 79 | border-color: transparent; 80 | box-shadow: 0 0 0 3px rgba(255, 255, 255, .25); 81 | } 82 | .border-top { border-top: 1px solid #e5e5e5; } 83 | .border-bottom { border-bottom: 1px solid #e5e5e5; } -------------------------------------------------------------------------------- /src/main/resources/static/css/bootstrap-responsive.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.2.2 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */@-ms-viewport{width:device-width}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:hover{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} 10 | -------------------------------------------------------------------------------- /src/main/resources/static/css/bootstrap-table.css: -------------------------------------------------------------------------------- 1 | /** 2 | * @author zhixin wen 3 | * version: 1.7.0 4 | * https://github.com/wenzhixin/bootstrap-table/ 5 | */ 6 | 7 | .bootstrap-table .table { 8 | margin-bottom: 0 !important; 9 | border-bottom: 1px solid #dddddd; 10 | border-collapse: collapse !important; 11 | border-radius: 1px; 12 | } 13 | 14 | .bootstrap-table .table, 15 | .bootstrap-table .table > tbody > tr > th, 16 | .bootstrap-table .table > tfoot > tr > th, 17 | .bootstrap-table .table > thead > tr > td, 18 | .bootstrap-table .table > tbody > tr > td, 19 | .bootstrap-table .table > tfoot > tr > td { 20 | padding: 8px !important; 21 | } 22 | 23 | .bootstrap-table .table.table-no-bordered > thead > tr > th, 24 | .bootstrap-table .table.table-no-bordered > tbody > tr > td { 25 | border-right: 2px solid transparent; 26 | } 27 | 28 | .fixed-table-container { 29 | position: relative; 30 | clear: both; 31 | border: 1px solid #dddddd; 32 | border-radius: 4px; 33 | -webkit-border-radius: 4px; 34 | -moz-border-radius: 4px; 35 | } 36 | 37 | .fixed-table-container.table-no-bordered { 38 | border: 1px solid transparent; 39 | } 40 | 41 | .fixed-table-footer, 42 | .fixed-table-header { 43 | height: 37px; /*cellHeight*/ 44 | overflow: hidden; 45 | border-radius: 4px 4px 0 0; 46 | -webkit-border-radius: 4px 4px 0 0; 47 | -moz-border-radius: 4px 4px 0 0; 48 | } 49 | 50 | .fixed-table-header { 51 | border-bottom: 1px solid #dddddd; 52 | } 53 | 54 | .fixed-table-footer { 55 | border-top: 1px solid #dddddd; 56 | } 57 | 58 | .fixed-table-body { 59 | overflow-x: auto; 60 | overflow-y: auto; 61 | height: 100%; 62 | } 63 | 64 | .fixed-table-container table { 65 | width: 100%; 66 | } 67 | 68 | .fixed-table-container thead th { 69 | height: 0; 70 | padding: 0; 71 | margin: 0; 72 | border-left: 1px solid #dddddd; 73 | } 74 | 75 | .fixed-table-container thead th:first-child { 76 | border-left: none; 77 | border-top-left-radius: 4px; 78 | -webkit-border-top-left-radius: 4px; 79 | -moz-border-radius-topleft: 4px; 80 | } 81 | 82 | .fixed-table-container thead th .th-inner { 83 | padding: 8px; 84 | line-height: 24px; 85 | vertical-align: top; 86 | overflow: hidden; 87 | text-overflow: ellipsis; 88 | white-space: nowrap; 89 | } 90 | 91 | .fixed-table-container thead th .sortable { 92 | cursor: pointer; 93 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAkElEQVQoz7X QMQ5AQBCF4dWQSJxC5wwax1Cq1e7BAdxD5SL+Tq/QCM1oNiJidwox0355mXnG/DrEtIQ6azioNZQxI0ykPhTQIwhCR+BmBYtlK7kLJYwWCcJA9M4qdrZrd8pPjZWPtOqdRQy320YSV17OatFC4euts6z39GYMKRPCTKY9UnPQ6P+GtMRfGtPnBCiqhAeJPmkqAAAAAElFTkSuQmCC'); 94 | background-position: right; 95 | background-repeat: no-repeat; 96 | padding-right: 30px; 97 | } 98 | 99 | .fixed-table-container tbody td { 100 | border-left: 1px solid #dddddd; 101 | } 102 | 103 | .fixed-table-container tbody tr:first-child td { 104 | border-top: none; 105 | } 106 | 107 | .fixed-table-container tbody td:first-child { 108 | border-left: none; 109 | } 110 | 111 | /* the same color with .active */ 112 | .fixed-table-container tbody .selected td { 113 | background-color: #f5f5f5; 114 | } 115 | 116 | .fixed-table-container .bs-checkbox { 117 | text-align: center; 118 | } 119 | 120 | .fixed-table-container .bs-checkbox .th-inner { 121 | padding: 8px 0; 122 | } 123 | 124 | .fixed-table-container input[type="radio"], 125 | .fixed-table-container input[type="checkbox"] { 126 | margin: 0 auto !important; 127 | } 128 | 129 | .fixed-table-container .no-records-found { 130 | text-align: center; 131 | } 132 | 133 | .fixed-table-pagination div.pagination, 134 | .fixed-table-pagination .pagination-detail { 135 | margin-top: 10px; 136 | margin-bottom: 10px; 137 | } 138 | 139 | .fixed-table-pagination div.pagination .pagination { 140 | margin: 0; 141 | } 142 | 143 | .fixed-table-pagination .pagination a { 144 | padding: 6px 12px; 145 | line-height: 1.428571429; 146 | } 147 | 148 | .fixed-table-pagination .pagination-info { 149 | line-height: 34px; 150 | margin-right: 5px; 151 | } 152 | 153 | .fixed-table-pagination .btn-group { 154 | position: relative; 155 | display: inline-block; 156 | vertical-align: middle; 157 | } 158 | 159 | .fixed-table-pagination .dropup .dropdown-menu { 160 | margin-bottom: 0; 161 | } 162 | 163 | .fixed-table-pagination .page-list { 164 | display: inline-block; 165 | } 166 | 167 | .fixed-table-toolbar .columns-left { 168 | margin-right: 5px; 169 | } 170 | 171 | .fixed-table-toolbar .columns-right { 172 | margin-left: 5px; 173 | } 174 | 175 | .fixed-table-toolbar .columns label { 176 | display: block; 177 | padding: 3px 20px; 178 | clear: both; 179 | font-weight: normal; 180 | line-height: 1.428571429; 181 | } 182 | 183 | .fixed-table-toolbar .bars, 184 | .fixed-table-toolbar .search, 185 | .fixed-table-toolbar .columns { 186 | position: relative; 187 | margin-top: 10px; 188 | margin-bottom: 10px; 189 | line-height: 34px; 190 | } 191 | 192 | .fixed-table-pagination li.disabled a { 193 | pointer-events: none; 194 | cursor: default; 195 | } 196 | 197 | .fixed-table-loading { 198 | display: none; 199 | position: absolute; 200 | top: 42px; 201 | right: 0; 202 | bottom: 0; 203 | left: 0; 204 | z-index: 99; 205 | background-color: #fff; 206 | text-align: center; 207 | } 208 | 209 | .fixed-table-body .card-view .title { 210 | font-weight: bold; 211 | display: inline-block; 212 | min-width: 30%; 213 | text-align: left !important; 214 | } 215 | 216 | /* support bootstrap 2 */ 217 | .fixed-table-body thead th .th-inner { 218 | box-sizing: border-box; 219 | } 220 | 221 | .table th, .table td { 222 | vertical-align: middle; 223 | box-sizing: border-box; 224 | } 225 | 226 | .fixed-table-toolbar .dropdown-menu { 227 | text-align: left; 228 | max-height: 300px; 229 | overflow: auto; 230 | } 231 | 232 | .fixed-table-toolbar .btn-group > .btn-group { 233 | display: inline-block; 234 | margin-left: -1px !important; 235 | } 236 | 237 | .fixed-table-toolbar .btn-group > .btn-group > .btn { 238 | border-radius: 0; 239 | } 240 | 241 | .fixed-table-toolbar .btn-group > .btn-group:first-child > .btn { 242 | border-top-left-radius: 4px; 243 | border-bottom-left-radius: 4px; 244 | } 245 | 246 | .fixed-table-toolbar .btn-group > .btn-group:last-child > .btn { 247 | border-top-right-radius: 4px; 248 | border-bottom-right-radius: 4px; 249 | } 250 | 251 | .bootstrap-table .table > thead > tr > th { 252 | vertical-align: bottom; 253 | border-bottom: 2px solid #ddd; 254 | } 255 | 256 | /* support bootstrap 3 */ 257 | .bootstrap-table .table thead > tr > th { 258 | padding: 0; 259 | margin: 0; 260 | } 261 | 262 | .pull-right .dropdown-menu { 263 | right: 0; 264 | left: auto; 265 | } 266 | 267 | /* calculate scrollbar width */ 268 | p.fixed-table-scroll-inner { 269 | width: 100%; 270 | height: 200px; 271 | } 272 | 273 | div.fixed-table-scroll-outer { 274 | top: 0; 275 | left: 0; 276 | visibility: hidden; 277 | width: 200px; 278 | height: 150px; 279 | overflow: hidden; 280 | } -------------------------------------------------------------------------------- /src/main/resources/static/css/style.css: -------------------------------------------------------------------------------- 1 | .error-input { 2 | border-color: #b94a48; 3 | margin-left: 5px; 4 | } 5 | 6 | .error-messages { 7 | color: #b94a48; 8 | } -------------------------------------------------------------------------------- /src/main/resources/static/images/springsecurity.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onjsdnjs/corespringsecurityfinal/eec4b30d8cc7157f347ef948c136a58fd1cbb284/src/main/resources/static/images/springsecurity.jpg -------------------------------------------------------------------------------- /src/main/resources/templates/admin/common/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/main/resources/templates/admin/common/top.html: -------------------------------------------------------------------------------- 1 | 2 | 4 |
5 | 12 |
13 | -------------------------------------------------------------------------------- /src/main/resources/templates/admin/config.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 |
7 |
8 | 22 |
23 |
24 |

여기는 환경설정 입니다.

25 |
26 |
27 |
28 |
29 |
30 | 31 | -------------------------------------------------------------------------------- /src/main/resources/templates/admin/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 |
10 |
11 | 16 |
17 |
18 |
19 |
20 |

Spring Security Administration

21 |
22 |
23 |
24 | 25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /src/main/resources/templates/admin/resource/detail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 |
9 |
10 | 15 |
16 |
17 | 18 |
19 | 20 |
21 | 22 |
23 |
24 | 25 |
26 | 27 |
28 | 29 |
30 |
31 |
32 | 33 |
34 | 35 |
36 |
37 |
38 | 39 |
40 | 41 |
42 |
43 |
44 | 45 |
46 | 52 |
53 |
54 |
55 |
56 | 57 | 58 | 목록 59 | 삭제 60 |
61 |
62 |
63 |
64 |
65 | 66 | -------------------------------------------------------------------------------- /src/main/resources/templates/admin/resource/list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 |
10 |
11 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | 37 |
리소스명리소스타입HttpMethod순서
38 |
39 |

리소드 등록

40 |
41 |
42 |
43 | 44 | -------------------------------------------------------------------------------- /src/main/resources/templates/admin/role/detail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 |
9 |
10 | 15 |
16 |
17 | 18 |
19 | 20 |
21 | 22 |
23 |
24 | 25 |
26 | 27 |
28 | 29 |
30 |
31 |
32 |
33 | 34 | 목록 35 |
36 |
37 |
38 |
39 |
40 | 41 | -------------------------------------------------------------------------------- /src/main/resources/templates/admin/role/list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 |
9 |
10 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 |
권한명권한설명
33 |
34 |

권한 등록

35 |
36 |
37 |
38 | 39 | -------------------------------------------------------------------------------- /src/main/resources/templates/admin/user/detail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 |
9 |
10 | 15 |
16 |
17 | 18 |
19 | 20 |
21 | 22 |
23 |
24 | 25 |
26 | 27 |
28 | 29 |
30 |
31 |
32 | 33 |
34 | 35 |
36 |
37 |
38 | 39 |
40 | 41 |
42 |
43 |
44 | 45 |
46 | 50 |
51 |
52 |
53 |
54 | 55 | 목록 56 |
57 |
58 |
59 |
60 |
61 | 62 | -------------------------------------------------------------------------------- /src/main/resources/templates/admin/user/list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 |
10 |
11 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 39 | 40 | 41 |
이름이메일나이권한
42 |
43 |
44 | 45 | 46 | -------------------------------------------------------------------------------- /src/main/resources/templates/aop/method.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 |
7 |
8 | 26 |
27 |
28 |

Method

29 |
30 |
31 |
32 |
33 | 34 | -------------------------------------------------------------------------------- /src/main/resources/templates/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 |
7 |
8 | 26 |
27 |
28 |

DASHBOARD

29 |
30 |

Core Spring Security 에 오신 것을 환영합니다.

31 |
32 |
33 |
34 |
35 |
36 | 37 | -------------------------------------------------------------------------------- /src/main/resources/templates/layout/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | 8 |
9 |
10 | -------------------------------------------------------------------------------- /src/main/resources/templates/layout/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Home 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/resources/templates/layout/top.html: -------------------------------------------------------------------------------- 1 | 2 | 4 |
5 | 17 |
18 | -------------------------------------------------------------------------------- /src/main/resources/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 40 | 41 |
42 |
43 | 64 |
65 | 66 | -------------------------------------------------------------------------------- /src/main/resources/templates/user/login/denied.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 |
7 |
8 | 22 |
23 |
24 |

님은 접근 권한이 없습니다.

25 |
26 |

27 |
28 |
29 |
30 |
31 |
32 | 33 | -------------------------------------------------------------------------------- /src/main/resources/templates/user/login/register.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 |
8 |
9 |
10 |
11 | 12 |
13 | 14 |
15 |
16 | 17 |
18 | 19 |
20 | 21 |
22 |
23 |
24 | 25 |
26 | 27 |
28 |
29 |
30 | 31 |
32 | 33 |
34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 |
42 |
43 | 44 |
45 |
46 |
47 |
48 |
49 | 50 | -------------------------------------------------------------------------------- /src/main/resources/templates/user/messages.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 |
7 |
8 | 22 |
23 |
24 |

여기는 MESSAGE 보내는 곳입니다.

25 |
26 |
27 |
28 |
29 |
30 | 31 | -------------------------------------------------------------------------------- /src/main/resources/templates/user/mypage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 |
7 |
8 | 22 |
23 |
24 |

여기는 MYPAGE 입니다.

25 |
26 |
27 |
28 |
29 |
30 | 31 | -------------------------------------------------------------------------------- /src/test/java/io/security/corespringsecurity/CorespringsecurityApplicationTests.java: -------------------------------------------------------------------------------- 1 | package io.security.corespringsecurity; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class CorespringsecurityApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | --------------------------------------------------------------------------------