用 Java 做一个“可登录 + 权限控制”的网站(Spring Boot + Session 实战)

用 Java 做一个“可登录 + 权限控制”的网站(Spring Boot + Session 实战)

很多网站做到“能访问页面”只是第一步,真正上线后很快会遇到第二类需求:后台登录、权限控制、管理页面。如果没有一套清晰的登录流程,站点维护会非常痛苦:后台入口随便暴露、接口不加拦截、会话管理混乱,最后只能靠“隐藏路径”硬撑。

这篇文章用 Spring Boot + Session(不引入复杂框架) 实现一个最小可用的登录系统:

  • 前台页面正常访问
  • /admin 必须登录才能访问
  • 登录成功写入 Session
  • 退出登录清理 Session
  • 用拦截器统一做权限校验 并给出完整示例代码,你可以直接套进自己的网站骨架。


一、目标效果与路由规划

我们要实现这些访问规则:

  • / 首页(公开)
  • /login 登录页(公开)
  • /admin 后台首页(需要登录)
  • /logout 退出登录(需要登录也可公开,效果一样)

登录策略:Session 里保存 user 对象或用户名。 拦截策略:用 HandlerInterceptor 拦截 /admin/**


二、核心依赖(pom.xml)

只需要 web + thymeleaf:

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

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


三、推荐目录结构(清晰可扩展)

src/main/java/com/example/site
  ├── SiteApplication.java
  ├── controller
  │    ├── PublicController.java
  │    └── AdminController.java
  ├── auth
  │    ├── AuthInterceptor.java
  │    └── WebConfig.java

src/main/resources ├── templates │ ├── index.html │ ├── login.html │ └── admin.html └── static/css/site.css


四、控制器:公开页面与登录逻辑

1)PublicController(首页 + 登录 + 退出)

PublicController.java

package com.example.site.controller;

import jakarta.servlet.http.HttpSession; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*;

@Controller public class PublicController {

private static final String SESSION_USER = "LOGIN_USER";

@GetMapping("/")
public String index(Model model, HttpSession session) {
    Object user = session.getAttribute(SESSION_USER);
    model.addAttribute("user", user);
    return "index";
}

@GetMapping("/login")
public String loginPage() {
    return "login";
}

@PostMapping("/login")
public String doLogin(@RequestParam String username,
                      @RequestParam String password,
                      HttpSession session,
                      Model model) {

    // ✅ 演示用:实际项目请改为数据库校验 + 密码加密
    if ("admin".equals(username) && "123456".equals(password)) {
        session.setAttribute(SESSION_USER, username);
        return "redirect:/admin";
    }

    model.addAttribute("error", "用户名或密码不正确");
    return "login";
}

@GetMapping("/logout")
public String logout(HttpSession session) {
    session.removeAttribute(SESSION_USER);
    return "redirect:/";
}

}

说明:

  • 这里先用硬编码账号演示(admin/123456)
  • 真正上线时改成数据库用户表,并对密码做加密校验(BCrypt 等)


五、后台控制器:AdminController(受保护页面)

AdminController.java

package com.example.site.controller;

import jakarta.servlet.http.HttpSession; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping;

@Controller public class AdminController {

@GetMapping("/admin")
public String adminHome(HttpSession session, Model model) {
    model.addAttribute("user", session.getAttribute("LOGIN_USER"));
    return "admin";
}

}


六、权限拦截器:AuthInterceptor(核心)

这一步是“能不能上线”的关键:把权限逻辑集中管理,不要每个控制器里写 if。

AuthInterceptor.java

package com.example.site.auth;

import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; import org.springframework.web.servlet.HandlerInterceptor;

public class AuthInterceptor implements HandlerInterceptor {

private static final String SESSION_USER = "LOGIN_USER";

@Override
public boolean preHandle(HttpServletRequest request,
                         HttpServletResponse response,
                         Object handler) throws Exception {
    HttpSession session = request.getSession(false);
    Object user = (session == null) ? null : session.getAttribute(SESSION_USER);

    if (user == null) {
        response.sendRedirect("/login");
        return false;
    }
    return true;
}

}


七、注册拦截器:WebConfig

WebConfig.java

package com.example.site.auth;

import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.*;

@Configuration public class WebConfig implements WebMvcConfigurer {

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new AuthInterceptor())
            .addPathPatterns("/admin/**")     // ✅ 需要登录的路径
            .excludePathPatterns("/login", "/logout", "/css/**", "/js/**", "/images/**");
}

}

这样一来,只要访问 /admin 或未来的 /admin/posts/admin/settings,都会自动校验登录状态。


八、页面模板:index / login / admin

1)index.html

<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="utf-8"/>
  <title>Java 网站首页</title>
  <link rel="stylesheet" href="/css/site.css"/>
</head>
<body>
<div class="container">
  <h1>首页</h1>

&lt;div th:if="${user != null}"&gt; &lt;p&gt;当前登录用户:<b></b>&lt;/p&gt; <a href="/admin">进入后台</a> <a href="/logout">退出登录</a> &lt;/div&gt;

&lt;div th:if="${user == null}"&gt; &lt;p&gt;你尚未登录。&lt;/p&gt; <a href="/login">去登录</a> &lt;/div&gt; &lt;/div&gt; &lt;/body&gt; &lt;/html&gt;

2)login.html

&lt;html lang="zh" xmlns:th="http://www.thymeleaf.org"&gt;
&lt;head&gt;
  &lt;meta charset="utf-8"/&gt;
  &lt;title&gt;登录&lt;/title&gt;
  &lt;link rel="stylesheet" href="/css/site.css"/&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div class="container"&gt;
  &lt;h1&gt;后台登录&lt;/h1&gt;

  &lt;p class="error" th:if="${error}" th:text="${error}"&gt;&lt;/p&gt;

  &lt;form method="post" action="/login"&gt;
    &lt;label&gt;用户名&lt;/label&gt;
    &lt;input name="username" placeholder="admin"/&gt;

    &lt;label&gt;密码&lt;/label&gt;
    &lt;input name="password" type="password" placeholder="123456"/&gt;

    &lt;button class="btn" type="submit"&gt;登录&lt;/button&gt;
  &lt;/form&gt;

  <a href="/">返回首页</a>
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;

3)admin.html

&lt;html lang="zh" xmlns:th="http://www.thymeleaf.org"&gt;
&lt;head&gt;
  &lt;meta charset="utf-8"/&gt;
  &lt;title&gt;后台&lt;/title&gt;
  &lt;link rel="stylesheet" href="/css/site.css"/&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div class="container"&gt;
  &lt;h1&gt;后台首页&lt;/h1&gt;
  &lt;p&gt;欢迎你,<b></b>&lt;/p&gt;

  &lt;p&gt;这里可以扩展:文章管理、产品管理、系统设置等。&lt;/p&gt;

  <a href="/">回到首页</a>
  <a href="/logout">退出登录</a>
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;


九、简单 CSS(可复用)

site.css

body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Arial; background:#f6f7fb; }
.container { max-width: 760px; margin: 40px auto; background:#fff; padding: 26px; border-radius: 14px; }
label { display:block; margin-top: 12px; color:#333; font-size: 14px; }
input { width:100%; padding:10px; margin-top:6px; border:1px solid #ddd; border-radius:10px; }
.btn { display:inline-block; margin-top:14px; padding:10px 14px; background:#111; color:#fff; text-decoration:none; border-radius:10px; border:0; cursor:pointer; }
.link { margin-left:10px; color:#333; text-decoration:none; }
.error { background:#fff2f2; border:1px solid #ffd2d2; padding:10px; border-radius:10px; color:#b10000; }


十、运行与验证

启动:

mvn spring-boot:run

访问流程:

  1. 打开 /admin 会自动跳转到 /login
  2. 输入 admin / 123456 登录
  3. 登录成功进入 /admin
  4. 点击退出登录,回到首页


十一、上线前必须做的三件事(非常关键)

如果你准备上线到公网,至少做这三件事:

  1. 把账号密码从硬编码换成数据库(并使用 BCrypt 加密)
  2. 开启 HTTPS(Nginx 反代 + 证书)
  3. 给后台路径加二次保护(例如 /admin 改成不可猜路径 + 限流/验证码)

评论 0