먼저 로그인에 필요한 것이 무엇인지 생각해 보세요. 가장 간단한 경우에는 사용자 이름과 비밀번호를 데이터베이스와 비교한 다음 일치하면 개인 페이지로 이동하고 그렇지 않으면 로그인 페이지로 돌아가서 묻는 메시지를 표시합니다. 사용자 이름과 비밀번호가 올바르지 않습니다. 이 프로세스에는 권한 역할도 있어야 하며 전체 세션 동안 계속되어야 합니다. 이 아이디어를 사용하면 비교를 위해 데이터베이스의 사용자 이름과 비밀번호를 Spring 보안에 넘겨주고 보안이 관련 점프를 하도록 하고 보안이 전체 세션에 걸쳐 권한 역할과 사용자 이름을 배치하는 데 도움을 줍니다. 실제로 올바른 사용자 이름과 비밀번호를 제공하고 보안을 구성하기만 하면 됩니다.
디렉토리
준비
로그인 페이지
개인 페이지
스프링 보안 구성 시작
1. 스프링 시작 보안
2. 권한 구성
3. UserDetailService 작성
먼저 데이터베이스 테이블을 준비
CREATE TABLE `user` ( `username` varchar(255) NOT NULL, `password` char(255) NOT NULL, `roles` enum('MEMBER','MEMBER,LEADER','SUPER_ADMIN') NOT NULL DEFAULT 'MEMBER', PRIMARY KEY (`username`), KEY `username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
PS: 여기서 내용에 주의하세요. Roles, LEADER도 MEMBER입니다. 이러한 방식으로 LEADER는 MEMBER 권한을 갖게 됩니다. 물론 나중에 설명할 애플리케이션에서 판단을 내릴 수도 있습니다.
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form"%> <html> <head> <title>登录</title> </head> <body> <div > <sf:form action="${pageContext.request.contextPath}/log" method="POST" commandName="user"> <!-- spring表单标签,用于模型绑定和自动添加隐藏的CSRF token标签 --> <h1 >登录</h1> <c:if test="${error==true}"><p style="color: red">错误的帐号或密码</p></c:if> <!-- 登陆失败会显示这句话 --> <c:if test="${logout==true}"><p >已退出登录</p></c:if> <!-- 退出登陆会显示这句话 --> <sf:input path="username" name="user.username" placeholder="输入帐号" /><br /> <sf:password path="password" name="user.password" placeholder="输入密码" /><br /> <input id="remember-me" name="remember-me" type="checkbox"/> <!-- 是否记住我功能勾选框 --> <label for="remember-me">一周内记住我</label> <input type="submit" class="sumbit" value="提交" > </sf:form> </div> </body> </html>
개인 페이지
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false"%> <%@taglib prefix="security" uri="http://www.springframework.org/security/tags" %> <%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form"%> <html> <head> <title>欢迎你,<security:authentication property="principal.username" var="username"/>${username}</title> <!-- 登陆成功会显示名字,这里var保存用户名字到username变量,下面就可以通过EL获取 --> </head> <body> <security:authorize access="isAuthenticated()"><h3>登录成功!${username}</h3></security:authorize> <!-- 登陆成功会显示名字 --> <security:authorize access="hasRole('MEMBER')"> <!-- MENBER角色就会显示 security:authorize标签里的内容--> <p>你是MENBER</p> </security:authorize> <security:authorize access="hasRole('LEADER')"> <p>你是LEADER</p> </security:authorize> <sf:form id="logoutForm" action="${pageContext.request.contextPath}/logout" method="post"> <!-- 登出按钮,注意这里是post,get是会登出失败的 --> <a href="#" onclick="document.getElementById('logoutForm').submit();">注销</a> </sf:form> </body> </html>
스프링 보안 구성 시작
스프링 보안 시작
@Order(2)public class WebSecurityAppInit extends AbstractSecurityWebApplicationInitializer{ }
AbstractSecurityWebApplicationInitializer를 상속하면 스프링 보안이 자동으로 준비됩니다. 여기서 @Order(2)는 springmvc(순수 주석 구성)와 스프링 보안을 함께 시작할 때 발생한 오류입니다. 나중에 보안을 시작하기 위해 이것을 추가했습니다. 이 문제는 피할 수 있습니다. @Order(2)를 작성하지 않아도 문제가 없다면 걱정하지 마세요.
2. 권한 설정
@Configuration @EnableWebSecurity @ComponentScan("com.chuanzhi.workspace.service.impl.*") public class WebSecurityConfig extends WebSecurityConfigurerAdapter{ @Autowired private UserDetailService userDetailService; //如果userDetailService没有扫描到就加上面的@ComponentScan @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/me").hasAnyRole("MEMBER","SUPER_ADMIN") //个人首页只允许拥有MENBER,SUPER_ADMIN角色的用户访问 .anyRequest().authenticated() .and() .formLogin() .loginPage("/").permitAll() //这里程序默认路径就是登陆页面,允许所有人进行登陆 .loginProcessingUrl("/log") //登陆提交的处理url .failureForwardUrl("/?error=true") //登陆失败进行转发,这里回到登陆页面,参数error可以告知登陆状态 .defaultSuccessUrl("/me") //登陆成功的url,这里去到个人首页 .and() .logout().logoutUrl("/logout").permitAll().logoutSuccessUrl("/?logout=true") //按顺序,第一个是登出的url,security会拦截这个url进行处理,所以登出不需要我们实现,第二个是登出url,logout告知登陆状态 .and() .rememberMe() .tokenValiditySeconds(604800) //记住我功能,cookies有限期是一周 .rememberMeParameter("remember-me") //登陆时是否激活记住我功能的参数名字,在登陆页面有展示 .rememberMeCookieName("workspace"); //cookies的名字,登陆后可以通过浏览器查看cookies名字 } @Override public void configure(WebSecurity web) throws Exception { super.configure(web); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailService); //配置自定义userDetailService } }
3. UserDetailService 작성
스프링 시큐리티는 사용자 정보를 얻기 위한 서비스를 제공하는데, 주로 사용자를 확인하기 위한 정보로 보안을 제공한다. . 여기에서 우리는 필요에 따라 사용자 정의할 수 있습니다. 내가 하는 일은 사용자 이름을 기반으로 데이터베이스에서 사용자 정보를 얻은 다음 후속 처리를 위해 보안 담당자에게 넘겨주는 것입니다.
@Service(value = "userDetailService") public class UserDetailService implements UserDetailsService { @Autowired private UserRepository repository; public UserDetailService(UserRepository userRepository){ this.repository = userRepository; //用户仓库,这里不作说明了 } public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = repository.findUserByUsername(username); if (user==null) throw new UsernameNotFoundException("找不到该账户信息!"); //抛出异常,会根据配置跳到登录失败页面 List<GrantedAuthority> list = new ArrayList<GrantedAuthority>(); //GrantedAuthority是security提供的权限类, getRoles(user,list); //获取角色,放到list里面 org.springframework.security.core.userdetails.User auth_user = new org.springframework.security.core.userdetails.User(user.getUsername(),user.getPassword(),list); //返回包括权限角色的User给security return auth_user; } /** * 获取所属角色 * @param user * @param list */ public void getRoles(User user,List<GrantedAuthority> list){ for (String role:user.getRoles().split(",")) { list.add(new SimpleGrantedAuthority("ROLE_"+role)); //权限如果前缀是ROLE_,security就会认为这是个角色信息,而不是权限,例如ROLE_MENBER就是MENBER角色,CAN_SEND就是CAN_SEND权限 } } }
기억하고 싶다면 기능의 효율성 다음에 로그인 페이지에 들어가서 개인 홈페이지로 바로 이동하면 이 컨트롤러 코드를 살펴볼 수 있습니다.
/** * 登录页面 * @param * @return */ @RequestMapping(value = "/") public String login(Model model,User user ,@RequestParam(value = "error",required = false) boolean error ,@RequestParam(value = "logout",required = false) boolean logout,HttpServletRequest request){ model.addAttribute(user); //如果已经登陆跳转到个人首页 Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if(authentication!=null&& !authentication.getPrincipal().equals("anonymousUser")&& authentication.isAuthenticated()) return "me"; if(error==true) model.addAttribute("error",error); if(logout==true) model.addAttribute("logout",logout); return "login"; }
결과 표시: