spring secutiry oauth2.0认证制授权 --基于session的认证流程

1.1认证流程

spring secutiry oauth2.0认证制授权 --基于session的认证流程

spring secutiry oauth2.0认证制授权 --基于session的认证流程

基于Session认证方式的流程,用户认证成功后,在服务端生成用户相关的数据保存在session(当前会话),而发给客户端。

基于Session的认证机制由servlet规范定制,servlet容器已实现,用户通过httpsession的操作方法即可实现,如下是httpsession相关的api

方法 含义
HttpSession getSession(Boolean create) 获取当前httpsession对象
void setAttributes(String name,Object value) 向session对象中存放对象
object getAttributes(String name) 从session中获取对象
void invalidate 使用httpsession失效

1.2创建工程

     本案例工程使用maven进行构建,使用Spring MVC,servlet 3.0实现

     创建maven工程security-springmvc,工程结构如下:

pom.xml的配置

4.0.0com.wangjunji.securitysecurity-springmvc1.0-SNAPSHOTwarsecurity-springmvc Maven Webapphttp://www.example.comUTF-81.81.8org.springframeworkspring-webmvc5.1.5.RELEASEjavax.servletjavax.servlet-api3.0.1org.projectlomboklombok1.18.8junitjunit4.11testsecurity-springmvcmaven-clean-plugin3.1.0maven-resources-plugin3.0.2maven-compiler-plugin3.8.0maven-surefire-plugin2.22.1maven-war-plugin3.2.2maven-install-plugin2.5.2maven-deploy-plugin2.8.2

 

1.3spring 容器配置

在config包下定义ApplicationConfig.java,它对应Web.xml中contextLoderListener配置

//springbean.xml

package com.wangjunji.security.springmvc.config;


import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

@Configuration
@ComponentScan(basePackages = "com.wangjunji.security.springmvc",
        excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)})
public class ApplicationConfig {
    //在此配置除了controller的其它bean,比如:数据库链接池,事务管理器,业务bean
}

1.4 servletContext配置

本案例采用servlet 3.0无web.xml方式的conifg包下定webConfig.java,它对应于dispatcherSevlet配置

//springmvc.xml

package com.wangjunji.security.springmvc.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.wangjunji.security.springmvc",
                includeFilters = {@ComponentScan.Filter(type= FilterType.ANNOTATION,value = Controller.class)})
public class WebConfig implements WebMvcConfigurer {
    @Bean
    public InternalResourceViewResolver viewResolver(){
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/views"); //需要注意,需要创建相应的目录 
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

}

1.5加载spring容器

在init包下定义spring容器初始化类springApplicatinlnitIaizer,此类实现WebApplicationInitializer接口,spring 容器启动时加载webappliction所有接口的所有实现类

package com.wangjunji.security.springmvc.init;

import com.wangjunji.security.springmvc.config.ApplicationConfig;
import com.wangjunji.security.springmvc.config.WebConfig;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
//这个就相当于Web.xml
public class SpringApplicationInitalizer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class[] getRootConfigClasses() {
        return new Class[]{ApplicationConfig.class};

    }

    @Override
    protected Class[] getServletConfigClasses() {
        return new Class[] {WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

 1.6认证页面

在Webapp/WEB-INF/views下定义认证页面login.jsp,本案例只是测试认证流程,页面没有添加css样式,页面实现可填 入用户名,密码,触发登录将提交表单信息至/login,内容如下


在WebConfig.java中新增如下配置,将直接导向login.jsp页面

  @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("login");

    }

启动项目,访问、路径

spring secutiry oauth2.0认证制授权 --基于session的认证流程

1.7 认证接口

先创建登陆用户实体类

package com.wangjunji.security.springmvc.model;

import lombok.Data;


public class AuthenticationRequest {
    //认证请求参数,账号,密码
    /**
     * 用户名
     */
    private String username;
    /**
     * 用户密码
     */
    private String password;

    public String getUsername() {
        return username;
    }

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

    public String getPassword() {
        return password;
    }

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

//再创建用户账号实体类,数据库里面的

package com.wangjunji.security.springmvc.model;

import lombok.Data;


public class UserDto {
    //用户的身份
    private String id;
    private String username;
    private String password;
    private String fullname;
    private String mobile;

    public UserDto(String id, String username, String password, String fullname, String mobile) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.fullname = fullname;
        this.mobile = mobile;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

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

    public String getPassword() {
        return password;
    }

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

    public String getFullname() {
        return fullname;
    }

    public void setFullname(String fullname) {
        this.fullname = fullname;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }
}

//创建认证接口

package com.wangjunji.security.springmvc.service;

import com.wangjunji.security.springmvc.model.AuthenticationRequest;
import com.wangjunji.security.springmvc.model.UserDto;

/**
 * create by wangjunji
 */
public interface AuthenticationService {
    /**
     * 用户认证
     * @param authenticationRequest 用户请求,账号和密码
     */
    UserDto authentication(AuthenticationRequest authenticationRequest);
}

//创建认证实体类

package com.wangjunji.security.springmvc.service;

import com.wangjunji.security.springmvc.model.AuthenticationRequest;
import com.wangjunji.security.springmvc.model.UserDto;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;

@Service
public class AuthenticationServiceImpl implements AuthenticationService {
    /**
     * 用户认证,校验用户身份信息
     * @param authenticationRequest 用户请求,账号和密码
     * @return
     */
    @Override
    public UserDto authentication(AuthenticationRequest authenticationRequest) {
        if(authenticationRequest == null
                || StringUtils.isEmpty(authenticationRequest.getUsername())
                ||StringUtils.isEmpty(authenticationRequest.getPassword())){
            throw new RuntimeException("账号或密码为空");
        }
        UserDto userDto = getUserDto(authenticationRequest.getUsername());
        if(userDto == null){
            throw  new RuntimeException("用户不存在");
        }
        if(! userDto.getPassword().equals( authenticationRequest.getPassword())){
            throw new RuntimeException("密码不正确");
        }
        return userDto;




    }

    //模拟用户查询
    public UserDto getUserDto(String name){
        return userMap.get(name);
    }

    //用户信息
    private MapuserMap = new HashMap<>();
     {
        userMap.put("zhangsan",new UserDto("1010","zhangsan","123","张三","133443"));
        userMap.put("lisi",new UserDto("1011","1isi","456","李四","144553"));
     }
}

//创建登陆controller

package com.wangjunji.security.springmvc.controller;

import com.wangjunji.security.springmvc.model.AuthenticationRequest;
import com.wangjunji.security.springmvc.model.UserDto;
import com.wangjunji.security.springmvc.service.AuthenticationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LoginController {

    @Autowired
    AuthenticationService authenticationService;
    @RequestMapping(value="/login")
    public String login(AuthenticationRequest authenticationRequest){
        UserDto authentication = authenticationService.authentication(authenticationRequest);
        return authentication.getUsername()+"登陆成功";
    }

}

1.8 实现会话功能

会话是指用户登入系统后,系统会记住该用户的登陆状态,它可以连续操作直到退出系统的过程

认证的目的是对系统资源的保护,每次对资源的访问,系统必须得知道谁在访问资源,才能对该请求进行合法性拦截。因此,在认证成功后,一会把认证成功的用户信息放入sessionk ,在后续的请求中,系统能够从Session中获取当前用户,用这样的方式来实现会话机制。

(1)增加会话控制

首先在UserDao中定义一个SESSION_USER_KEY,作为Session中存放登录用户信息的key

 public static final String SEESION_USER_KEY = "_user";

然后修改LoginController,认证成功后,把用户信息放入当前会话。并增加用户登出方法,登出时将session置为失效

package com.wangjunji.security.springmvc.controller;

import com.wangjunji.security.springmvc.model.AuthenticationRequest;
import com.wangjunji.security.springmvc.model.UserDto;
import com.wangjunji.security.springmvc.service.AuthenticationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;

@RestController
public class LoginController {

    @Autowired
    AuthenticationService authenticationService;
    @RequestMapping(value="/login",produces = {"text/plain;charset=UTF-8"})
    public String login(AuthenticationRequest authenticationRequest, HttpSession httpSession){
        UserDto authentication = authenticationService.authentication(authenticationRequest);
        httpSession.setAttribute(UserDto.SEESION_USER_KEY,authentication);
        return authentication.getUsername()+"登陆成功";
    }

    @GetMapping(value = "/session",produces = {"text/plain;charset=UTF-8"})
    public String getSession(HttpSession session){
        Object attribute = session.getAttribute(UserDto.SEESION_USER_KEY);
        if(attribute == null){
            return "匿名访问";
        }else {
            UserDto attribute1 = (UserDto) attribute;
            return  attribute1.getFullname();
        }
    }

    @GetMapping(value = "/logout",produces = {"text/plain;charset=UTF-8"})
    public String invalidateSession(HttpSession session){
        session.invalidate();
        return "退出";
    }

}

2.0实现授权

第一步:给用户进行权限赋值

package com.wangjunji.security.springmvc.model;

import lombok.Data;

import java.util.Set;


public class UserDto {
    //用户的身份
    public static final String SEESION_USER_KEY = "_user";
    private String id;
    private String username;
    private String password;
    private String fullname;
    private String mobile;
    private Setauthoritites;

    public SetgetAuthoritites() {
        return authoritites;
    }

    public void setAuthoritites(Setauthoritites) {
        this.authoritites = authoritites;
    }

    public UserDto(String id, String username, String password, String fullname, String mobile, Setauthoritites) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.fullname = fullname;
        this.mobile = mobile;
        this.authoritites = authoritites;
    }




    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

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

    public String getPassword() {
        return password;
    }

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

    public String getFullname() {
        return fullname;
    }

    public void setFullname(String fullname) {
        this.fullname = fullname;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }
}

第二步:给用户增加相应的权限

package com.wangjunji.security.springmvc.service;

import com.wangjunji.security.springmvc.model.AuthenticationRequest;
import com.wangjunji.security.springmvc.model.UserDto;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

@Service
public class AuthenticationServiceImpl implements AuthenticationService {
    /**
     * 用户认证,校验用户身份信息
     * @param authenticationRequest 用户请求,账号和密码
     * @return
     */
    @Override
    public UserDto authentication(AuthenticationRequest authenticationRequest) {
        if(authenticationRequest == null
                || StringUtils.isEmpty(authenticationRequest.getUsername())
                ||StringUtils.isEmpty(authenticationRequest.getPassword())){
            throw new RuntimeException("账号或密码为空");
        }
        UserDto userDto = getUserDto(authenticationRequest.getUsername());
        if(userDto == null){
            throw  new RuntimeException("用户不存在");
        }
        if(! userDto.getPassword().equals( authenticationRequest.getPassword())){
            throw new RuntimeException("密码不正确");
        }
        return userDto;




    }

    //模拟用户查询
    public UserDto getUserDto(String name){
        return userMap.get(name);
    }

    //用户信息
    private MapuserMap = new HashMap<>();
     {
         Setauthoritites1 = new HashSet<>();
         Setauthoritites2 = new HashSet<>();
         authoritites1.add("p1"); //这个p1我们人为让它和/r/r1对应
         authoritites2.add("p2"); //这个p2我们人为让它和/r/r2对应
        userMap.put("zhangsan",new UserDto("1010","zhangsan","123","张三","133443",authoritites1));
        userMap.put("lisi",new UserDto("1011","1isi","456","李四","144553",authoritites2));
     }
}

第三步:创建conrtoller 

package com.wangjunji.security.springmvc.controller;

import com.wangjunji.security.springmvc.model.AuthenticationRequest;
import com.wangjunji.security.springmvc.model.UserDto;
import com.wangjunji.security.springmvc.service.AuthenticationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;

@RestController
public class LoginController {

    @Autowired
    AuthenticationService authenticationService;
    @RequestMapping(value="/login",produces = {"text/plain;charset=UTF-8"})
    public String login(AuthenticationRequest authenticationRequest, HttpSession httpSession){
        UserDto authentication = authenticationService.authentication(authenticationRequest);
        httpSession.setAttribute(UserDto.SEESION_USER_KEY,authentication);
        return authentication.getUsername()+"登陆成功";
    }

    @GetMapping(value = "/session",produces = {"text/plain;charset=UTF-8"})
    public String getSession(HttpSession session){
        Object attribute = session.getAttribute(UserDto.SEESION_USER_KEY);
        if(attribute == null){
            return "匿名访问";
        }else {
            UserDto attribute1 = (UserDto) attribute;
            return  attribute1.getFullname();
        }
    }

    @GetMapping(value = "/logout",produces = {"text/plain;charset=UTF-8"})
    public String invalidateSession(HttpSession session){
        session.invalidate();
        return "退出";
    }

    @GetMapping(value = "/r/r1",produces = {"text/plain;charset=UTF-8"})
    public String rr1(HttpSession session){
        Object attribute = session.getAttribute(UserDto.SEESION_USER_KEY);
        if(attribute == null){
            return "匿名访问";
        }else {
            UserDto attribute1 = (UserDto) attribute;
            return  attribute1.getFullname()+"访问/r/r1";
        }
    }

    @GetMapping(value = "/r/r2",produces = {"text/plain;charset=UTF-8"})
    public String rr2(HttpSession session){
        Object attribute = session.getAttribute(UserDto.SEESION_USER_KEY);
        if(attribute == null){
            return "匿名访问";
        }else {
            UserDto attribute1 = (UserDto) attribute;
            return  attribute1.getFullname()+"访问/r/r2";
        }
    }

}

第四步,创建拦截器

package com.wangjunji.security.springmvc.interceptor;

import com.wangjunji.security.springmvc.model.UserDto;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@Component //拦载器
public class SimpleAuthticationInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //这个方法中校验用户请求的url是否在用户请求的权限范围内
        //取用户身份
        response.setContentType("text/html;charset=utf-8");
        Object attribute = request.getSession().getAttribute(UserDto.SEESION_USER_KEY);
        if(attribute == null){
            //没有认证,提示登录
            writeContent(response,"请登录");
        }
        UserDto attribute1 = (UserDto) attribute;
        //请示的url
        String reqestURL = request.getRequestURI();
        if(attribute1.getAuthoritites().contains("p1") && reqestURL.contains("/r/r1")){
            return true;
        }

        if(attribute1.getAuthoritites().contains("p2") && reqestURL.contains("/r/r2")){
            return true;
        }
        writeContent(response ,"没有权限");

        return false;
    }

    private void writeContent(HttpServletResponse response,String msg) throws IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print(msg);
        writer.close();
        response.resetBuffer();
    }

}

第五步:注册拦截器

 @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(simpleAuthticationInterceptor).addPathPatterns("/r/**");
    }

//注意需要指定拦载的url

 

上一篇:MongoDB–Spring Data MongoDB详细的操作手册(增删改查)


下一篇:寒假学习进度