1. 전체 구조

2. Spring Starter Project 생성

생성 과정은 생략 하겠다.

3. pom.xml

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-test</artifactId>
	<scope>test</scope>
</dependency>
<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-test</artifactId>
	<scope>test</scope>
</dependency>


<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>mybatis-spring-boot-starter</artifactId>
	<version>2.2.0</version>
</dependency>

<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>8.0.25</version>
</dependency>		

<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-taglibs</artifactId>
</dependency>

<dependency>
  <groupId>org.apache.tomcat.embed</groupId>
  <artifactId>tomcat-embed-jasper</artifactId>
</dependency>

<dependency>
  <groupId>jstl</groupId>
  <artifactId>jstl</artifactId>
  <version>1.2</version>
</dependency>

4. Security Config

package com.iut.mes.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import com.iut.mes.service.UserService;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	UserService userService;
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()

		// 페이지 권한 설정
		.antMatchers("/user/admin/**").access("hasAuthority('ADMIN')")
		.antMatchers("/user/myinfo").access("hasAuthority('USER')")

		// .permitAll() : 모두 허용
		.antMatchers("/", "/user/signup", "/user/denied", "/user/logout/result").permitAll()
		.anyRequest().authenticated()
		.and()

		// 로그인 설정
		.formLogin().loginPage("/user/loginPage")  // 로그인 페이지
		.loginProcessingUrl("/login")  // 로그인 폼 전송 URL
		.defaultSuccessUrl("/user/login/result")  // 로그인 성공시 이동 페이지
		.permitAll()
		.and()

		// 로그아웃 설정
		.logout().logoutRequestMatcher(new AntPathRequestMatcher("/user/logout"))
		.logoutSuccessUrl("/user/logout/result").invalidateHttpSession(true)
		.and()

		// 접근 거부 설정
		.exceptionHandling().accessDeniedPage("/user/denied")
		.and()
		.csrf().disable();
	}

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userService).passwordEncoder(userService.passwordEncoder());
	}
}

5. Controller

package com.iut.mes.controller;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.iut.mes.domain.User;
import com.iut.mes.mapper.UserMapper;
import com.iut.mes.service.UserServiceImpl;

@Controller
public class UserController {
	@Autowired UserMapper userMapper;

	@Autowired UserServiceImpl userservice;

    // 메인 페이지
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String index() {
        return "index";
    }

    // 회원가입 페이지
    @GetMapping("/user/signup")
    public String dispSignup() {
        return "signup";
    }

    // 회원가입 처리
    @PostMapping("/user/signup")
    public String execSignup(User user) {
    	System.out.println(user);
    	List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
		authorities.add(new SimpleGrantedAuthority("USER"));
		user.setAuthorities(authorities);
    	userservice.createUser(user);
        return "redirect:/user/login";
    }

    // 로그인 페이지
    @GetMapping("/user/loginPage")
    public String dispLogin() {
        return "login";
    }

    // 로그인 결과 페이지
    @GetMapping("/user/login/result")
    public String dispLoginResult() {
        return "loginSuccess";
    }

    // 로그아웃 결과 페이지
    @GetMapping("/user/logout/result")
    public String dispLogout() {
        return "logout";
    }

    // 접근 거부 페이지
    @GetMapping("/user/denied")
    public String dispDenied() {
        return "denied";
    }

    // 내 정보 페이지
    @GetMapping("/user/info")
    public String dispMyInfo() {
        return "myinfo";
    }

    // 어드민 페이지
    @GetMapping("/user/admin")
    public String dispAdmin() {
        return "admin";
    }
}

6. User Domain

package com.iut.mes.domain;

import java.util.Collection;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

public class User implements UserDetails {
	
	private static final long serialVersionUID = 5177294317961485740L;

	private String username;
    private String password;
    private String name;
    private boolean isAccountNonExpired;
    private boolean isAccountNonLocked;
    private boolean isCredentialsNonExpired;
    private boolean isEnabled;
    private Collection<? extends GrantedAuthority> authorities;
   
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
         return authorities;
    }

    @Override
    public String getPassword() {
         return password;
    }

    @Override
    public String getUsername() {
         return username;
    }

    @Override
    public boolean isAccountNonExpired() {
         return isAccountNonExpired;
    }

    @Override
    public boolean isAccountNonLocked() {
         return isAccountNonLocked;
    }

    @Override
    public boolean isCredentialsNonExpired() {
         return isCredentialsNonExpired;
    }

    @Override
    public boolean isEnabled() {
         return isEnabled;
    }

    public String getName() {
         return name;
    }

    public void setName(String name) {
         this.name = name;
    }

    public void setUsername(String username) {
         this.username = username;
    }

    public void setPassword(String password) {
         this.password = password;
    }

    public void setAccountNonExpired(boolean isAccountNonExpired) {
         this.isAccountNonExpired = isAccountNonExpired;
    }

    public void setAccountNonLocked(boolean isAccountNonLocked) {
         this.isAccountNonLocked = isAccountNonLocked;
    }

    public void setCredentialsNonExpired(boolean isCredentialsNonExpired) {
         this.isCredentialsNonExpired = isCredentialsNonExpired;
    }

    public void setEnabled(boolean isEnabled) {
         this.isEnabled = isEnabled;
    }

    public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
         this.authorities = authorities;
    }

	@Override
	public String toString() {
		return "User [username=" + username + ", password=" + password + ", name=" + name + ", isAccountNonExpired="
				+ isAccountNonExpired + ", isAccountNonLocked=" + isAccountNonLocked + ", isCredentialsNonExpired="
				+ isCredentialsNonExpired + ", isEnabled=" + isEnabled + "]";
	}

	public User(String username, String password, String name, boolean isAccountNonExpired, boolean isAccountNonLocked,
			boolean isCredentialsNonExpired, boolean isEnabled) {
		super();
		this.username = username;
		this.password = password;
		this.name = name;
		this.isAccountNonExpired = isAccountNonExpired;
		this.isAccountNonLocked = isAccountNonLocked;
		this.isCredentialsNonExpired = isCredentialsNonExpired;
		this.isEnabled = isEnabled;
	}
}

7. mapper

package com.iut.mes.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.iut.mes.domain.User;

@Mapper
public interface UserMapper {
	public List<User> Userlist();
	public User readUser(String username);
	public List<String> readAuthority(String username);
	public void createUser(User user);
	public void createAuthority(User user);
	public void deleteUser(String username);
	public void deleteAuthority(String username);
}

8. User Service

interface

package com.iut.mes.service;

import java.util.Collection;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;

import com.iut.mes.domain.User;

public interface UserService extends UserDetailsService {
     Collection<GrantedAuthority> getAuthorities(String username);
     public void createUser(User user);
     public void deleteUser(String username);
     public PasswordEncoder passwordEncoder();
}

class

package com.iut.mes.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import com.iut.mes.domain.User;
import com.iut.mes.mapper.UserMapper;

@Service
public class UserServiceImpl implements UserService {

	@Autowired
	UserMapper userMapper;
	private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		User user = userMapper.readUser(username);
		if(user==null) {
			throw new UsernameNotFoundException(username);
		}
		user.setAuthorities(getAuthorities(username));
		return user;
	}
	
	public Collection<GrantedAuthority> getAuthorities(String username) {
        List<String> string_authorities = userMapper.readAuthority(username);
        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        for (String authority : string_authorities) {
             authorities.add(new SimpleGrantedAuthority(authority));
        }
        return authorities;
   }

	@Override
	public void createUser(User user) {
		String rawPassword = user.getPassword();
		String encodedPassword = new BCryptPasswordEncoder().encode(rawPassword);
		user.setPassword(encodedPassword);
		userMapper.createUser(user);
		userMapper.createAuthority(user);
	}

	@Override
	public void deleteUser(String username) {
		userMapper.deleteUser(username);
		userMapper.deleteAuthority(username);
	}

	@Override
	public PasswordEncoder passwordEncoder() {
		return this.passwordEncoder;
	}
}

9. query

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.iut.mes.mapper.UserMapper">
	<select id="Userlist" resultType="User">
		SELECT * FROM user
	</select>

	<select id="readUser" parameterType="String" resultType="User">
		SELECT * FROM user WHERE username = #{username}
	</select>

	<select id="readAuthority" parameterType="String" resultType="String">
          SELECT authority_name FROM authority WHERE username = #{username}
     </select>

	<insert id="createUser" parameterType="User">
		INSERT INTO user (username, password, name, isAccountNonExpired,
		isAccountNonLocked, isCredentialsNonExpired, isEnabled)
		VALUES (#{username}, #{password}, #{name}, #{isAccountNonExpired},
		#{isAccountNonLocked}, #{isCredentialsNonExpired}, #{isEnabled})
	</insert>

	<insert id="createAuthority"
		parameterType="org.springframework.security.core.GrantedAuthority">
		INSERT INTO authority (username, authority_name)
		VALUES
		<foreach item="item" collection="authorities" separator=",">
			(#{username}, #{item.authority})
		</foreach>
	</insert>

	<delete id="deleteUser" parameterType="String">
		DELETE FROM user WHERE username = #{username}
	</delete>

	<delete id="deleteAuthority" parameterType="String">
		DELETE FROM authority WHERE username = #{username}
	</delete>
</mapper>

10. jsp

첫 페이지(index.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>MAIN</title>
</head>
<body>
	<h1>MAIN PAGE</h1>
    <hr>
    <sec:authorize access="isAnonymous()"><a href="/user/loginPage">LOGIN</a></sec:authorize>
    <sec:authorize access="isAuthenticated()"><a href="/user/logout">LOGOUT</a></sec:authorize>
    <sec:authorize access="isAnonymous()"><a href="/user/signup">SIGNUP</a></sec:authorize>
    <sec:authorize access="hasAuthority('ADMIN') or hasAuthority('USER')"><a href="/user/info">MY INFO</a></sec:authorize><br>
    <sec:authorize access="hasAuthority('USER')"><a href="/user/admin">ADMIN</a></sec:authorize><br>
</body>
</html>

로그인 페이지 (login.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>LOGIN</title>
</head>
<body>
    <h1>LOGIN</h1>
    <hr>

	<form action="/login" method="post">
        <input type="text" name="username" placeholder="INPUT YOUR ID">
        <input type="password" name="password" placeholder="INPUT YOUR PASSWORD">
        <button type="submit">LOGIN</button>
    </form>    
</body>
</html>

회원 가입 페이지 (signup.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

<!DOCTYPE html>
<html lang="kr">
<head>
    <meta charset="UTF-8">
    <title>SIGN IN</title>
</head>
<body>
    <h1>SIGN IN</h1>
    <hr>
	<form action="/user/signup" method="post">
        <input type="text" name="username" placeholder="INPUT YOUR ID">
        <input type="password" name="password" placeholder="INPUT YOUR PASSWORD">
        <input type="text" name="name" placeholder="INPUT YOUR NAME">
        <input type="hidden" name="isAccountNonExpired" value="true">
        <input type="hidden" name="isAccountNonLocked" value="true">
        <input type="hidden" name="isCredentialsNonExpired" value="true">
        <input type="hidden" name="isEnabled" value="true">
        <button type="submit">SIGN IN</button>
    </form>
</body>
</html>

로그인 성공 페이지 (loginSuccess.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8"	pageEncoding="UTF-8"%>
<%@ taglib prefix="sec"	uri="http://www.springframework.org/security/tags"%>

<!DOCTYPE html>
<html lang="en" xmlns:sec="" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>LOGIN SUCCESS</title>
</head>
<body>
	<h1>LOGIN SUCCESS</h1>
	<hr>
	<p>
		<sec:authorize access="isAuthenticated()">
			<sec:authentication property="principal" var="user" />
			<div>ID : ${user.name}</div>
			<div>Authorities : ${user.authorities}</div>
		</sec:authorize>
	</p>
    <sec:authorize access="hasAuthority('ADMIN') or hasAuthority('USER')"><a href="/user/info">MY INFO</a></sec:authorize><br>
    <sec:authorize access="hasAuthority('USER')"><a href="/user/admin">ADMIN</a></sec:authorize><br>
	
	<a href="/">GO MAIN</a>
</body>
</html>

접근거부 페이지(denied.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Access Denied</title>
</head>
<body>
    <h1>Access Denied</h1>
    <hr />
</body>
</html>

ADMIN role로 들어갈 수 있는 화면 (admin.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>ADMIN</title>
</head>
<body>
    <h1>ADMIN......</h1>
    <hr />
</body>
</html>

내 정보 페이지 (myinfo.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>MY INFO</title>
</head>
<body>
    <h1>MY INFO PAGE...</h1>
    <hr>
</body>
</html>

로그아웃 페이지 (logout.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>LOGOUT</title>
</head>
<body>
    <h1>LOGOUT!!!!</h1>
    <hr>
    <a href="/">GO MAIN</a>
</body>
</html>

부록 : spring security 태그라이브러리 사용

hasAuthority('Role Name')

해당 권한이 있을 경우

<sec:authorize access="hasAuthority('ADMIN')">
</sec:authorize>

hasAnyAuthority('Role Name')

포함된 권한 중 하나라도 있을 경우

<sec:authorize access="hasAnyAuthority('USER')">
</sec:authorize>

isAuthenticated()

권한에 관계없이 로그인 인증을 받은 경우

<sec:authorize access="isAuthenticated()">
</sec:authorize>

isAuthenticated()

권한에 관계없이 인증에 성공했고, 자동 로그인이 비활성인 경우

<sec:authorize access="isFullyAuthenticated()">
</sec:authorize>

isAnonymous()

권한이 없는 익명의 사용자일 경우

<sec:authorize access="isAnonymous()">
</sec:authorize>

isRememberMe()

자동 로그인을 사용하는 경우

<sec:authorize access="isRememberMe()">
</sec:authorize>

permitAll

모든 경우 출력함

<sec:authorize access="permitAll">
</sec:authorize>

denyAll

모든 경우 출력하지 않음

<sec:authorize access="denyAll">
</sec:authorize>

0개의 댓글

Powered by GraphCDN, the GraphQL CDN